Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
dddf414c
Commit
dddf414c
authored
Apr 30, 2015
by
Eric Tune
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #7195 from mbruzek/add-charms
Add the Juju charms to Kubernetes
parents
441a4e6f
74c00d43
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
58 changed files
with
2042 additions
and
63 deletions
+2042
-63
README.md
cluster/juju/bundles/README.md
+197
-0
local.yaml
cluster/juju/bundles/local.yaml
+50
-0
.gitignore
cluster/juju/charms/trusty/.gitignore
+2
-0
.bzrignore
cluster/juju/charms/trusty/kubernetes-master/.bzrignore
+1
-0
.gitignore
cluster/juju/charms/trusty/kubernetes-master/.gitignore
+5
-0
.vendor-rc
cluster/juju/charms/trusty/kubernetes-master/.vendor-rc
+5
-0
Makefile
cluster/juju/charms/trusty/kubernetes-master/Makefile
+29
-0
README.md
cluster/juju/charms/trusty/kubernetes-master/README.md
+101
-0
config.yaml
cluster/juju/charms/trusty/kubernetes-master/config.yaml
+9
-0
copyright
cluster/juju/charms/trusty/kubernetes-master/copyright
+13
-0
apiserver.upstart.tmpl
...rms/trusty/kubernetes-master/files/apiserver.upstart.tmpl
+20
-0
controller-manager.upstart.tmpl
...y/kubernetes-master/files/controller-manager.upstart.tmpl
+20
-0
distribution.conf.tmpl
...rms/trusty/kubernetes-master/files/distribution.conf.tmpl
+6
-0
nginx.conf.tmpl
...uju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl
+39
-0
scheduler.upstart.tmpl
...rms/trusty/kubernetes-master/files/scheduler.upstart.tmpl
+20
-0
__init__.py
...er/juju/charms/trusty/kubernetes-master/hooks/__init__.py
+0
-0
config-changed
...juju/charms/trusty/kubernetes-master/hooks/config-changed
+2
-0
etcd-relation-changed
...arms/trusty/kubernetes-master/hooks/etcd-relation-changed
+2
-0
hooks.py
cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py
+211
-0
install
cluster/juju/charms/trusty/kubernetes-master/hooks/install
+2
-0
install.py
...ter/juju/charms/trusty/kubernetes-master/hooks/install.py
+90
-0
kubernetes_installer.py
...ms/trusty/kubernetes-master/hooks/kubernetes_installer.py
+91
-0
minions-api-relation-changed
...usty/kubernetes-master/hooks/minions-api-relation-changed
+2
-0
network-relation-changed
...s/trusty/kubernetes-master/hooks/network-relation-changed
+2
-0
setup.py
cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py
+30
-0
icon.svg
cluster/juju/charms/trusty/kubernetes-master/icon.svg
+0
-0
metadata.yaml
cluster/juju/charms/trusty/kubernetes-master/metadata.yaml
+19
-0
notes.txt
cluster/juju/charms/trusty/kubernetes-master/notes.txt
+75
-0
requirements.txt
...ter/juju/charms/trusty/kubernetes-master/requirements.txt
+5
-0
kubernetes_installer_test.py
...kubernetes-master/unit_tests/kubernetes_installer_test.py
+105
-0
test_install.py
...harms/trusty/kubernetes-master/unit_tests/test_install.py
+92
-0
.bzrignore
cluster/juju/charms/trusty/kubernetes/.bzrignore
+1
-0
.gitignore
cluster/juju/charms/trusty/kubernetes/.gitignore
+6
-0
.vendor-rc
cluster/juju/charms/trusty/kubernetes/.vendor-rc
+5
-0
Makefile
cluster/juju/charms/trusty/kubernetes/Makefile
+29
-0
README.md
cluster/juju/charms/trusty/kubernetes/README.md
+100
-0
copyright
cluster/juju/charms/trusty/kubernetes/copyright
+13
-0
cadvisor.upstart.tmpl
...juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl
+16
-0
kubelet.upstart.tmpl
.../juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl
+15
-0
proxy.upstart.tmpl
...er/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl
+12
-0
api-relation-changed
.../juju/charms/trusty/kubernetes/hooks/api-relation-changed
+2
-0
etcd-relation-changed
...juju/charms/trusty/kubernetes/hooks/etcd-relation-changed
+2
-0
hooks.py
cluster/juju/charms/trusty/kubernetes/hooks/hooks.py
+225
-0
install
cluster/juju/charms/trusty/kubernetes/hooks/install
+32
-0
kubernetes_installer.py
...ju/charms/trusty/kubernetes/hooks/kubernetes_installer.py
+52
-0
__init__.py
cluster/juju/charms/trusty/kubernetes/hooks/lib/__init__.py
+0
-0
registrator.py
...er/juju/charms/trusty/kubernetes/hooks/lib/registrator.py
+82
-0
network-relation-changed
...u/charms/trusty/kubernetes/hooks/network-relation-changed
+2
-0
start
cluster/juju/charms/trusty/kubernetes/hooks/start
+15
-0
icon.svg
cluster/juju/charms/trusty/kubernetes/icon.svg
+0
-0
metadata.yaml
cluster/juju/charms/trusty/kubernetes/metadata.yaml
+23
-0
requirements.txt
cluster/juju/charms/trusty/kubernetes/requirements.txt
+4
-0
test_registrator.py
...arms/trusty/kubernetes/unit_tests/lib/test_registrator.py
+45
-0
test_hooks.py
...er/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py
+8
-0
ubuntu-juju.sh
cluster/juju/prereqs/ubuntu-juju.sh
+5
-6
return-node-ips.py
cluster/juju/return-node-ips.py
+14
-0
util.sh
cluster/juju/util.sh
+51
-39
juju.md
docs/getting-started-guides/juju.md
+38
-18
No files found.
cluster/juju/bundles/README.md
0 → 100644
View file @
dddf414c
# kubernetes-bundle
The kubernetes-bundle allows you to deploy the many services of
Kubernetes to a cloud environment and get started using the Kubernetes
technology quickly.
## Kubernetes
Kubernetes is an open source system for managing containerized
applications. Kubernetes uses
[
Docker
](
http://docker.com
)
to run
containerized applications.
## Juju TL;DR
The
[
Juju
](
https://juju.ubuntu.com
)
system provides provisioning and
orchestration across a variety of clouds and bare metal. A juju bundle
describes collection of services and how they interelate.
`juju
quickstart`
allows you to bootstrap a deployment environment and
deploy a bundle.
## Dive in!
#### Install Juju Quickstart
You will need to
[
install the Juju client
](
https://juju.ubuntu.com/install/
)
and
`juju-quickstart`
as pre-requisites. To deploy the bundle use
`juju-quickstart`
which runs on Mac OS (
`brew install
juju-quickstart`
) or Ubuntu (
`apt-get install juju-quickstart`
).
### Deploy Kubernetes Bundle
Deploy Kubernetes onto any cloud and orchestrated directly in the Juju
Graphical User Interface using
`juju quickstart`
:
juju quickstart -i https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml
The command above does few things for you:
-
Starts a curses based gui for managing your cloud or MAAS credentials
-
Looks for a bootstrapped deployment environment, and bootstraps if
required. This will launch a bootstrap node in your chosen
deployment environment (machine 0).
-
Deploys the Juju GUI to your environment onto the bootstrap node.
-
Provisions 4 machines, and deploys the Kubernetes services on top of
them (Kubernetes-master, two Kubernetes minions using flannel, and etcd).
-
Orchestrates the relations among the services, and exits.
Now you should have a running Kubernetes. Run
`juju status
--format=oneline`
to see the address of your kubernetes master.
For further reading on
[
Juju Quickstart
](
https://pypi.python.org/pypi/juju-quickstart
)
### Using the Kubernetes Client
You'll need the Kubernetes command line client,
[
kubectl
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
to interact with the created cluster. The kubectl command is
installed on the kubernetes-master charm. If you want to work with
the cluster from your computer you will need to install the binary
locally (see instructions below).
You can access kubectl by a number ways using juju.
via juju run:
juju run --service kubernetes-master/0 "sudo kubectl get mi"
via juju ssh:
juju ssh kubernetes-master/0 -t "sudo kubectl get mi"
You may also
`juju ssh kubernetes-master/0`
and call kubectl from that
machine.
See the
[
kubectl documentation
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
for more details of what can be done with the command line tool.
### Scaling up the cluster
You can add capacity by adding more Docker units:
juju add-unit docker
### Known Limitations
Kubernetes currently has several platform specific functionality. For
example load balancers and persistence volumes only work with the
Google Compute provider at this time.
The Juju integration uses the Kubernetes null provider. This means
external load balancers and storage can't be directly driven through
Kubernetes config files at this time. We look forward to adding these
capabilities to the charms.
## More about the components the bundle deploys
### Kubernetes master
The master controls the Kubernetes cluster. It manages for the worker
nodes and provides the primary interface for control by the user.
### Kubernetes minion
The minions are the servers that perform the work. Minions must
communicate with the master and run the workloads that are assigned to
them.
### Flannel-docker
Flannel provides individual subnets for each machine in the cluster by
creating a
[
software defined networking
](
http://en.wikipedia.org/wiki/Software-defined_networking
)
.
### Docker
An open platform for distributed applications for developers and sysadmins.
### Etcd
Etcd persists state for Flannel and Kubernetes. It is a distributed
key-value store with an http interface.
## For further information on getting started with Juju
Juju has complete documentation with regard to setup, and cloud
configuration on it's own
[
documentation site
](
https://juju.ubuntu.com/docs/
)
.
-
[
Getting Started
](
https://juju.ubuntu.com/docs/getting-started.html
)
-
[
Using Juju
](
https://juju.ubuntu.com/docs/charms.html
)
## Installing the kubectl outside of kubernetes master machine
Download the Kuberentes release from:
https://github.com/GoogleCloudPlatform/kubernetes/releases and extract
the release, you can then just directly use the cli binary at
./kubernetes/platforms/linux/amd64/kubectl
You'll need the address of the kubernetes-master as environment variable :
juju status kubernetes-master/0
Grab the public-address there and export it as KUBERNETES_MASTER
environment variable :
export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080
And now you can run kubectl on the command line :
kubectl get mi
See the
[
kubectl documentation
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
for more details of what can be done with the command line tool.
## Hacking on the kubernetes-bundle and associated charms
The kubernetes-bundle is open source and available on github.com. If
you want to get started developing on the bundle you can clone it from
github. Often you will need the related charms which are also on
github.
mkdir ~/bundles
git clone https://github.com/whitmo/kubernetes-bundle.git ~/bundles/kubernetes-bundle
mkdir -p ~/charms/trusty
git clone https://github.com/whitmo/kubernetes-charm.git ~/charms/trusty/kubernetes
git clone https://github.com/whitmo/kubernetes-master-charm.git ~/charms/trusty/kubernetes-master
juju quickstart specs/develop.yaml
## How to contribute
Send us pull requests! We'll send you a cookie if they include tests and docs.
## Current and Most Complete Information
-
[
kubernetes-master charm on Github
](
https://github.com/whitmo/charm-kubernetes-master
)
-
[
kubernetes charm on GitHub
](
https://github.com/whitmo/charm-kubernetes
)
-
[
etcd charm on GitHub
](
https://github.com/whitmo/etcd-charm
)
-
[
Flannel charm on GitHub
](
https://github.com/chuckbutler/docker-flannel-charm
)
-
[
Docker charm on GitHub
](
https://github.com/chuckbutler/docker-charm
)
More information about the
[
Kubernetes project
](
https://github.com/GoogleCloudPlatform/kubernetes
)
or check out the
[
Kubernetes Documentation
](
https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs
)
for more details about the Kubernetes concepts and terminology.
Having a problem? Check the
[
Kubernetes issues database
](
https://github.com/GoogleCloudPlatform/kubernetes/issues
)
for related issues.
cluster/juju/bundles/local.yaml
0 → 100644
View file @
dddf414c
kubernetes-local
:
services
:
kubernetes-master
:
charm
:
local:trusty/kubernetes-master
annotations
:
"
gui-x"
:
"
600"
"
gui-y"
:
"
0"
expose
:
true
options
:
version
:
"
v0.15.0"
docker
:
charm
:
docker
branch
:
https://github.com/chuckbutler/docker-charm.git
num_units
:
2
options
:
latest
:
true
annotations
:
"
gui-x"
:
"
0"
"
gui-y"
:
"
0"
flannel-docker
:
charm
:
cs:trusty/flannel-docker
annotations
:
"
gui-x"
:
"
0"
"
gui-y"
:
"
300"
kubernetes
:
charm
:
local:trusty/kubernetes
annotations
:
"
gui-x"
:
"
300"
"
gui-y"
:
"
300"
etcd
:
charm
:
cs:~kubernetes/trusty/etcd
annotations
:
"
gui-x"
:
"
300"
"
gui-y"
:
"
0"
relations
:
-
-
"
flannel-docker:network"
-
"
docker:network"
-
-
"
flannel-docker:docker-host"
-
"
docker:juju-info"
-
-
"
flannel-docker:db"
-
"
etcd:client"
-
-
"
kubernetes:docker-host"
-
"
docker:juju-info"
-
-
"
etcd:client"
-
"
kubernetes:etcd"
-
-
"
etcd:client"
-
"
kubernetes-master:etcd"
-
-
"
kubernetes-master:minions-api"
-
"
kubernetes:api"
series
:
trusty
cluster/juju/charms/trusty/.gitignore
0 → 100644
View file @
dddf414c
/docker
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/.bzrignore
0 → 100644
View file @
dddf414c
.git
cluster/juju/charms/trusty/kubernetes-master/.gitignore
0 → 100644
View file @
dddf414c
*~
.bzr
.venv
unit_tests/__pycache__
*.pyc
cluster/juju/charms/trusty/kubernetes-master/.vendor-rc
0 → 100644
View file @
dddf414c
omit:
- .git
- .gitignore
- .gitmodules
- revision
cluster/juju/charms/trusty/kubernetes-master/Makefile
0 → 100644
View file @
dddf414c
build
:
virtualenv lint test
virtualenv
:
virtualenv .venv
.venv/bin/pip
install
-q
-r
requirements.txt
lint
:
virtualenv
@
.venv/bin/flake8 hooks unit_tests
--exclude
=
charmhelpers
@
.venv/bin/charm proof
test
:
virtualenv
@
CHARM_DIR
=
.
PYTHONPATH
=
./hooks .venv/bin/py.test
-v
unit_tests/
*
functional-test
:
@
bundletester
release
:
check-path virtualenv
@
.venv/bin/pip
install
git-vendor
@
.venv/bin/git-vendor
sync
-d
${
KUBERNETES_MASTER_BZR
}
check-path
:
ifndef
KUBERNETES_MASTER_BZR
$(error
KUBERNETES_MASTER_BZR
is
undefined)
endif
clean
:
rm
-rf
.venv
find
-name
*
.pyc
-delete
cluster/juju/charms/trusty/kubernetes-master/README.md
0 → 100644
View file @
dddf414c
# Kubernetes Master Charm
[
Kubernetes
](
https://github.com/googlecloudplatform/kubernetes
)
is an open
source system for managing containerized applications across multiple hosts.
Kubernetes uses
[
Docker
](
http://www.docker.io/
)
to package, instantiate and run
containerized applications.
The Kubernetes Juju charms enable you to run Kubernetes on all the cloud
platforms that Juju supports.
A Kubernetes deployment consists of several independent charms that can be
scaled to meet your needs
### Etcd
Etcd is a key value store for Kubernetes. All persistent master state
is stored in
`etcd`
.
### Flannel-docker
Flannel is a
[
software defined networking
](
http://en.wikipedia.org/wiki/Software-defined_networking
)
component that provides individual subnets for each machine in the cluster.
### Docker
Docker is an open platform for distributing applications for system administrators.
### Kubernetes master
The controlling unit in a Kubernetes cluster is called the master. It is the
main management contact point providing many management services for the worker
nodes.
### Kubernetes minion
The servers that perform the work are known as minions. Minions must be able to
communicate with the master and run the workloads that are assigned to them.
## Usage
#### Deploying the Development Focus
To deploy a Kubernetes environment in Juju :
juju deploy cs:~kubernetes/trusty/etcd
juju deploy cs:trusty/flannel-docker
juju deploy cs:trusty/docker
juju deploy local:trusty/kubernetes-master
juju deploy local:trusty/kubernetes
juju add-relation etcd flannel-docker
juju add-relation flannel-docker:network docker:network
juju add-relation flannel-docker:docker-host docker
juju add-relation etcd kubernetes
juju add-relation etcd kubernetes-master
juju add-relation kubernetes kubernetes-master
#### Deploying the recommended configuration
A bundle can be used to deploy Kubernetes onto any cloud it can be
orchestrated directly in the Juju Graphical User Interface, when using
`juju quickstart`
:
juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml
For more information on the recommended bundle deployment, see the
[
Kubernetes bundle documentation
](
https://github.com/whitmo/bundle-kubernetes
)
#### Post Deployment
To interact with the kubernetes environment, either build or
[
download
](
https://github.com/GoogleCloudPlatform/kubernetes/releases
)
the
[
kubectl
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
binary (available in the releases binary tarball) and point it to the master with :
$ juju status kubernetes-master | grep public
public-address: 104.131.108.99
$ export KUBERNETES_MASTER="104.131.108.99"
# Configuration
For you convenience this charm supports changing the version of kubernetes binaries.
This can be done through the Juju GUI or on the command line:
juju set kubernetes version=”v0.10.0”
If the charm does not already contain the tar file with the desired architecture
and version it will attempt to download the kubernetes binaries using the gsutil
command.
Congratulations you know have deployed a Kubernetes environment! Use the
[
kubectl
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
to interact with the environment.
# Kubernetes information
-
[
Kubernetes github project
](
https://github.com/GoogleCloudPlatform/kubernetes
)
-
[
Kubernetes issue tracker
](
https://github.com/GoogleCloudPlatform/kubernetes/issues
)
-
[
Kubernetes Documenation
](
https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs
)
-
[
Kubernetes releases
](
https://github.com/GoogleCloudPlatform/kubernetes/releases
)
cluster/juju/charms/trusty/kubernetes-master/config.yaml
0 → 100644
View file @
dddf414c
options
:
version
:
type
:
string
default
:
"
v0.15.0"
description
:
|
The kubernetes release to use in this charm. The binary files are
compiled from the source identified by this tag in github. Using the
value of "source" will use the master kubernetes branch when compiling
the binaries.
cluster/juju/charms/trusty/kubernetes-master/copyright
0 → 100644
View file @
dddf414c
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
cluster/juju/charms/trusty/kubernetes-master/files/apiserver.upstart.tmpl
0 → 100644
View file @
dddf414c
description "Kubernetes Controller"
start on runlevel [2345]
stop on runlevel [!2345]
limit nofile 20000 20000
kill timeout 30 # wait 30s between SIGTERM and SIGKILL.
exec /usr/local/bin/apiserver \
--address=%(api_bind_address)s \
--etcd_servers=%(etcd_servers)s \
--logtostderr=true \
--portal_net=10.244.240.0/20
cluster/juju/charms/trusty/kubernetes-master/files/controller-manager.upstart.tmpl
0 → 100644
View file @
dddf414c
description "Kubernetes Controller"
start on runlevel [2345]
stop on runlevel [!2345]
limit nofile 20000 20000
kill timeout 30 # wait 30s between SIGTERM and SIGKILL.
exec /usr/local/bin/controller-manager \
--address=%(bind_address)s \
--logtostderr=true \
--master=%(api_server_address)s
cluster/juju/charms/trusty/kubernetes-master/files/distribution.conf.tmpl
0 → 100644
View file @
dddf414c
server {
listen %(api_bind_address)s:80;
location %(web_uri)s {
alias /opt/kubernetes/_output/local/bin/linux/amd64/;
}
}
cluster/juju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl
0 → 100644
View file @
dddf414c
# HTTP/HTTPS server
#
server {
listen 80;
server_name localhost;
root html;
index index.html index.htm;
# ssl on;
# ssl_certificate /usr/share/nginx/server.cert;
# ssl_certificate_key /usr/share/nginx/server.key;
# ssl_session_timeout 5m;
# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
# ssl_prefer_server_ciphers on;
location / {
# auth_basic "Restricted";
# auth_basic_user_file /usr/share/nginx/htpasswd;
# Proxy settings
# disable buffering so that watch works
proxy_buffering off;
proxy_pass %(api_server_address)s;
proxy_connect_timeout 159s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
# Disable retry
proxy_next_upstream off;
# Support web sockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
cluster/juju/charms/trusty/kubernetes-master/files/scheduler.upstart.tmpl
0 → 100644
View file @
dddf414c
description "Kubernetes Scheduler"
start on runlevel [2345]
stop on runlevel [!2345]
limit nofile 20000 20000
kill timeout 30 # wait 30s between SIGTERM and SIGKILL.
exec /usr/local/bin/scheduler \
--address=%(bind_address)s \
--logtostderr=true \
--master=%(api_server_address)s
cluster/juju/charms/trusty/kubernetes-master/hooks/__init__.py
0 → 100644
View file @
dddf414c
cluster/juju/charms/trusty/kubernetes-master/hooks/config-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/hooks/etcd-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py
0 → 100755
View file @
dddf414c
#!/usr/bin/python
"""
The main hook file is called by Juju.
"""
import
contextlib
import
os
import
socket
import
subprocess
import
sys
from
charmhelpers.core
import
hookenv
,
host
from
kubernetes_installer
import
KubernetesInstaller
from
path
import
path
hooks
=
hookenv
.
Hooks
()
@contextlib.contextmanager
def
check_sentinel
(
filepath
):
"""
A context manager method to write a file while the code block is doing
something and remove the file when done.
"""
fail
=
False
try
:
yield
filepath
.
exists
()
except
:
fail
=
True
filepath
.
touch
()
raise
finally
:
if
fail
is
False
and
filepath
.
exists
():
filepath
.
remove
()
@hooks.hook
(
'config-changed'
)
def
config_changed
():
"""
On the execution of the juju event 'config-changed' this function
determines the appropriate architecture and the configured version to
create kubernetes binary files.
"""
hookenv
.
log
(
'Starting config-changed'
)
charm_dir
=
path
(
hookenv
.
charm_dir
())
config
=
hookenv
.
config
()
# Get the version of kubernetes to install.
version
=
config
[
'version'
]
# Get the package architecture, rather than the from the kernel (uname -m).
arch
=
subprocess
.
check_output
([
'dpkg'
,
'--print-architecture'
])
.
strip
()
kubernetes_dir
=
path
(
'/opt/kubernetes'
)
if
not
kubernetes_dir
.
exists
():
print
(
'The source directory {0} does not exist'
.
format
(
kubernetes_dir
))
print
(
'Was the kubernetes code cloned during install?'
)
exit
(
1
)
if
version
in
[
'source'
,
'head'
,
'master'
]:
branch
=
'master'
else
:
# Create a branch to a tag.
branch
=
'tags/{0}'
.
format
(
version
)
# Construct the path to the binaries using the arch.
output_path
=
kubernetes_dir
/
'_output/local/bin/linux'
/
arch
installer
=
KubernetesInstaller
(
arch
,
version
,
output_path
)
# Change to the kubernetes directory (git repository).
with
kubernetes_dir
:
# Create a command to get the current branch.
git_branch
=
'git branch | grep "
\
*" | cut -d" " -f2'
current_branch
=
subprocess
.
check_output
(
git_branch
,
shell
=
True
)
.
strip
()
print
(
'Current branch: '
,
current_branch
)
# Create the path to a file to indicate if the build was broken.
broken_build
=
charm_dir
/
'.broken_build'
# write out the .broken_build file while this block is executing.
with
check_sentinel
(
broken_build
)
as
last_build_failed
:
print
(
'Last build failed: '
,
last_build_failed
)
# Rebuild if the current version is different or last build failed.
if
current_branch
!=
version
or
last_build_failed
:
installer
.
build
(
branch
)
if
not
output_path
.
exists
():
broken_build
.
touch
()
else
:
print
(
'Notifying minions of verison '
+
version
)
# Notify the minions of a version change.
for
r
in
hookenv
.
relation_ids
(
'minions-api'
):
hookenv
.
relation_set
(
r
,
version
=
version
)
print
(
'Done notifing minions of version '
+
version
)
# Create the symoblic links to the right directories.
installer
.
install
()
relation_changed
()
hookenv
.
log
(
'The config-changed hook completed successfully.'
)
@hooks.hook
(
'etcd-relation-changed'
,
'minions-api-relation-changed'
)
def
relation_changed
():
template_data
=
get_template_data
()
# Check required keys
for
k
in
(
'etcd_servers'
,):
if
not
template_data
.
get
(
k
):
print
"Missing data for"
,
k
,
template_data
return
print
"Running with
\n
"
,
template_data
# Render and restart as needed
for
n
in
(
'apiserver'
,
'controller-manager'
,
'scheduler'
):
if
render_file
(
n
,
template_data
)
or
not
host
.
service_running
(
n
):
host
.
service_restart
(
n
)
# Render the file that makes the kubernetes binaries available to minions.
if
render_file
(
'distribution'
,
template_data
,
'conf.tmpl'
,
'/etc/nginx/sites-enabled/distribution'
)
or
\
not
host
.
service_running
(
'nginx'
):
host
.
service_reload
(
'nginx'
)
# Render the default nginx template.
if
render_file
(
'nginx'
,
template_data
,
'conf.tmpl'
,
'/etc/nginx/sites-enabled/default'
)
or
\
not
host
.
service_running
(
'nginx'
):
host
.
service_reload
(
'nginx'
)
# Send api endpoint to minions
notify_minions
()
def
notify_minions
():
print
(
"Notify minions."
)
config
=
hookenv
.
config
()
for
r
in
hookenv
.
relation_ids
(
'minions-api'
):
hookenv
.
relation_set
(
r
,
hostname
=
hookenv
.
unit_private_ip
(),
port
=
8080
,
version
=
config
[
'version'
])
def
get_template_data
():
rels
=
hookenv
.
relations
()
config
=
hookenv
.
config
()
template_data
=
{}
template_data
[
'etcd_servers'
]
=
","
.
join
([
"http://
%
s:
%
s"
%
(
s
[
0
],
s
[
1
])
for
s
in
sorted
(
get_rel_hosts
(
'etcd'
,
rels
,
(
'hostname'
,
'port'
)))])
template_data
[
'minions'
]
=
","
.
join
(
get_rel_hosts
(
'minions-api'
,
rels
))
template_data
[
'api_bind_address'
]
=
_bind_addr
(
hookenv
.
unit_private_ip
())
template_data
[
'bind_address'
]
=
"127.0.0.1"
template_data
[
'api_server_address'
]
=
"http://
%
s:
%
s"
%
(
hookenv
.
unit_private_ip
(),
8080
)
arch
=
subprocess
.
check_output
([
'dpkg'
,
'--print-architecture'
])
.
strip
()
template_data
[
'web_uri'
]
=
"/kubernetes/
%
s/local/bin/linux/
%
s/"
%
(
config
[
'version'
],
arch
)
_encode
(
template_data
)
return
template_data
def
_bind_addr
(
addr
):
if
addr
.
replace
(
'.'
,
''
)
.
isdigit
():
return
addr
try
:
return
socket
.
gethostbyname
(
addr
)
except
socket
.
error
:
raise
ValueError
(
"Could not resolve private address"
)
def
_encode
(
d
):
for
k
,
v
in
d
.
items
():
if
isinstance
(
v
,
unicode
):
d
[
k
]
=
v
.
encode
(
'utf8'
)
def
get_rel_hosts
(
rel_name
,
rels
,
keys
=
(
'private-address'
,)):
hosts
=
[]
for
r
,
data
in
rels
.
get
(
rel_name
,
{})
.
items
():
for
unit_id
,
unit_data
in
data
.
items
():
if
unit_id
==
hookenv
.
local_unit
():
continue
values
=
[
unit_data
.
get
(
k
)
for
k
in
keys
]
if
not
all
(
values
):
continue
hosts
.
append
(
len
(
values
)
==
1
and
values
[
0
]
or
values
)
return
hosts
def
render_file
(
name
,
data
,
src_suffix
=
"upstart.tmpl"
,
tgt_path
=
None
):
tmpl_path
=
os
.
path
.
join
(
os
.
environ
.
get
(
'CHARM_DIR'
),
'files'
,
'
%
s.
%
s'
%
(
name
,
src_suffix
))
with
open
(
tmpl_path
)
as
fh
:
tmpl
=
fh
.
read
()
rendered
=
tmpl
%
data
if
tgt_path
is
None
:
tgt_path
=
'/etc/init/
%
s.conf'
%
name
if
os
.
path
.
exists
(
tgt_path
):
with
open
(
tgt_path
)
as
fh
:
contents
=
fh
.
read
()
if
contents
==
rendered
:
return
False
with
open
(
tgt_path
,
'w'
)
as
fh
:
fh
.
write
(
rendered
)
return
True
if
__name__
==
'__main__'
:
hooks
.
execute
(
sys
.
argv
)
cluster/juju/charms/trusty/kubernetes-master/hooks/install
0 → 120000
View file @
dddf414c
install.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/hooks/install.py
0 → 100755
View file @
dddf414c
#!/usr/bin/python
import
setup
setup
.
pre_install
()
import
subprocess
from
charmhelpers.core
import
hookenv
from
charmhelpers
import
fetch
from
charmhelpers.fetch
import
archiveurl
from
path
import
path
def
install
():
install_packages
()
hookenv
.
log
(
'Installing go'
)
download_go
()
hookenv
.
log
(
'Adding kubernetes and go to the path'
)
strings
=
[
'export GOROOT=/usr/local/go
\n
'
,
'export PATH=$PATH:$GOROOT/bin
\n
'
,
'export KUBE_MASTER_IP=0.0.0.0
\n
'
,
'export KUBERNETES_MASTER=http://$KUBE_MASTER_IP
\n
'
,
]
update_rc_files
(
strings
)
hookenv
.
log
(
'Downloading kubernetes code'
)
clone_repository
()
hookenv
.
open_port
(
8080
)
hookenv
.
log
(
'Install complete'
)
def
download_go
():
"""
Kubernetes charm strives to support upstream. Part of this is installing a
fairly recent edition of GO. This fetches the golang archive and installs
it in /usr/local
"""
go_url
=
'https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz'
go_sha1
=
'5020af94b52b65cc9b6f11d50a67e4bae07b0aff'
handler
=
archiveurl
.
ArchiveUrlFetchHandler
()
handler
.
install
(
go_url
,
'/usr/local'
,
go_sha1
,
'sha1'
)
def
clone_repository
():
"""
Clone the upstream repository into /opt/kubernetes for deployment compilation
of kubernetes. Subsequently used during upgrades.
"""
repository
=
'https://github.com/GoogleCloudPlatform/kubernetes.git'
kubernetes_directory
=
'/opt/kubernetes'
command
=
[
'git'
,
'clone'
,
repository
,
kubernetes_directory
]
print
(
command
)
output
=
subprocess
.
check_output
(
command
)
print
(
output
)
def
install_packages
():
"""
Install required packages to build the k8s source, and syndicate between
minion nodes. In addition, fetch pip to handle python dependencies
"""
hookenv
.
log
(
'Installing Debian packages'
)
# Create the list of packages to install.
apt_packages
=
[
'build-essential'
,
'git'
,
'make'
,
'nginx'
,
'python-pip'
]
fetch
.
apt_install
(
fetch
.
filter_installed_packages
(
apt_packages
))
def
update_rc_files
(
strings
):
"""
Preseed the bash environment for ubuntu and root with K8's env vars to
make interfacing with the api easier. (see: kubectrl docs)
"""
rc_files
=
[
path
(
'/home/ubuntu/.bashrc'
),
path
(
'/root/.bashrc'
)]
for
rc_file
in
rc_files
:
lines
=
rc_file
.
lines
()
for
string
in
strings
:
if
string
not
in
lines
:
lines
.
append
(
string
)
rc_file
.
write_lines
(
lines
)
if
__name__
==
"__main__"
:
install
()
cluster/juju/charms/trusty/kubernetes-master/hooks/kubernetes_installer.py
0 → 100644
View file @
dddf414c
import
os
import
shlex
import
subprocess
from
path
import
path
def
run
(
command
,
shell
=
False
):
""" A convience method for executing all the commands. """
print
(
command
)
if
shell
is
False
:
command
=
shlex
.
split
(
command
)
output
=
subprocess
.
check_output
(
command
,
shell
=
shell
)
print
(
output
)
return
output
class
KubernetesInstaller
():
"""
This class contains the logic needed to install kuberentes binary files.
"""
def
__init__
(
self
,
arch
,
version
,
output_dir
):
""" Gather the required variables for the install. """
# The kubernetes-master charm needs certain commands to be aliased.
self
.
aliases
=
{
'kube-apiserver'
:
'apiserver'
,
'kube-controller-manager'
:
'controller-manager'
,
'kube-proxy'
:
'kube-proxy'
,
'kube-scheduler'
:
'scheduler'
,
'kubectl'
:
'kubectl'
,
'kubelet'
:
'kubelet'
}
self
.
arch
=
arch
self
.
version
=
version
self
.
output_dir
=
path
(
output_dir
)
def
build
(
self
,
branch
):
""" Build kubernetes from a github repository using the Makefile. """
# Remove any old build artifacts.
make_clean
=
'make clean'
run
(
make_clean
)
# Always checkout the master to get the latest repository information.
git_checkout_cmd
=
'git checkout master'
run
(
git_checkout_cmd
)
# When checking out a tag, delete the old branch (not master).
if
branch
!=
'master'
:
git_drop_branch
=
'git branch -D {0}'
.
format
(
self
.
version
)
print
(
git_drop_branch
)
rc
=
subprocess
.
call
(
git_drop_branch
.
split
())
if
rc
!=
0
:
print
(
'returned:
%
d'
%
rc
)
# Make sure the git repository is up-to-date.
git_fetch
=
'git fetch origin {0}'
.
format
(
branch
)
run
(
git_fetch
)
if
branch
==
'master'
:
git_reset
=
'git reset --hard origin/master'
run
(
git_reset
)
else
:
# Checkout a branch of kubernetes so the repo is correct.
checkout
=
'git checkout -b {0} {1}'
.
format
(
self
.
version
,
branch
)
run
(
checkout
)
# Create an environment with the path to the GO binaries included.
go_path
=
(
'/usr/local/go/bin'
,
os
.
environ
.
get
(
'PATH'
,
''
))
go_env
=
os
.
environ
.
copy
()
go_env
[
'PATH'
]
=
':'
.
join
(
go_path
)
print
(
go_env
[
'PATH'
])
# Compile the binaries with the make command using the WHAT variable.
make_what
=
"make all WHAT='cmd/kube-apiserver cmd/kubectl "
\
"cmd/kube-controller-manager plugin/cmd/kube-scheduler "
\
"cmd/kubelet cmd/kube-proxy'"
print
(
make_what
)
rc
=
subprocess
.
call
(
shlex
.
split
(
make_what
),
env
=
go_env
)
def
install
(
self
,
install_dir
=
path
(
'/usr/local/bin'
)):
""" Install kubernetes binary files from the output directory. """
if
not
install_dir
.
isdir
():
install_dir
.
makedirs_p
()
# Create the symbolic links to the real kubernetes binaries.
for
key
,
value
in
self
.
aliases
.
iteritems
():
target
=
self
.
output_dir
/
key
if
target
.
exists
():
link
=
install_dir
/
value
if
link
.
exists
():
link
.
remove
()
target
.
symlink
(
link
)
else
:
print
(
'Error target file {0} does not exist.'
.
format
(
target
))
exit
(
1
)
cluster/juju/charms/trusty/kubernetes-master/hooks/minions-api-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/hooks/network-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py
0 → 100644
View file @
dddf414c
def
pre_install
():
"""
Do any setup required before the install hook.
"""
install_charmhelpers
()
install_path
()
def
install_charmhelpers
():
"""
Install the charmhelpers library, if not present.
"""
try
:
import
charmhelpers
# noqa
except
ImportError
:
import
subprocess
subprocess
.
check_call
([
'apt-get'
,
'install'
,
'-y'
,
'python-pip'
])
subprocess
.
check_call
([
'pip'
,
'install'
,
'charmhelpers'
])
def
install_path
():
"""
Install the path.py library, when not present.
"""
try
:
import
path
# noqa
except
ImportError
:
import
subprocess
subprocess
.
check_call
([
'apt-get'
,
'install'
,
'-y'
,
'python-pip'
])
subprocess
.
check_call
([
'pip'
,
'install'
,
'path.py'
])
cluster/juju/charms/trusty/kubernetes-master/icon.svg
0 → 100644
View file @
dddf414c
This diff is collapsed.
Click to expand it.
cluster/juju/charms/trusty/kubernetes-master/metadata.yaml
0 → 100644
View file @
dddf414c
name
:
kubernetes-master
summary
:
Container Cluster Management Master
description
:
|
Provides a kubernetes api endpoint, scheduler for managing containers.
maintainers
:
-
Matt Bruzek <matt.bruzek@canonical.com>
-
Whit Morriss <whit.morriss@canonical.com>
-
Charles Butler <charles.butler@canonical.com>
tags
:
-
ops
-
network
provides
:
client-api
:
interface
:
kubernetes-client
minions-api
:
interface
:
kubernetes-api
requires
:
etcd
:
interface
:
etcd
cluster/juju/charms/trusty/kubernetes-master/notes.txt
0 → 100644
View file @
dddf414c
kubernetes-master
-----------------
notes on src
------------
current provider responsibilities
- instances
- load blanacers
- zones (not useful as its only for apiserver).
provider functionality currently hardcoded to gce across codebase
- persistent storage
ideas
-----
- juju provider impl
- file provider for machines/minions
- openvpn as overlay per extant salt config.
cloud
-----
todo
----
- token auth file
- format csv -> token, user, uid
- config privileged
- config log-level
- config / check logs collection endpoint
- config / version and binary location via url
Q/A
----
https://botbot.me/freenode/google-containers/2014-10-17/?msg=23696683&page=6
Q. The new volumes/storage provider api appears to be hardcoded to
gce.. Is there a plan to abstract that anytime soon?
A. effectively it is abstract enough for the moment, no plans to
change, but willing subject to suitable abstraction.
Q.The zone provider api appears to return the address only of the api
server afaics. How is that useful? afaics the better semantic would be
an attribute on the minions to instantiate multiple templates across
zones?
A. apparently not considered, current solution for ha is multiple k8s
per zone with external lb. pointed out this was inane.
Q. Several previous platforms supported have been moved to the icebox,
just curious what was subject to bitrot. the salt/shell script for
those platforms or something more api intrinsic?
A. apparently the change to ship binaries instead of build from src
broke them.. somehow.
Q. i'm mostly interested in flannel due to its portability. Does the
inter pod networking setup need to include the other components of the
system, ie does api talk directly to containers, or only via kubelet.
A. api server only talks to kubelet
Q. Status of HA?
A. not done yet, election package merged, nothing using it.
Afaics design discussion doesn't take place on the list.
Q. Is minion registration supported, ie. bypassing cloud provider
filter all instances via regex match?
A. not done yet, pull request in review for minions in etcd (not
found, perhaps merged)
-------------
cadvisor usage helper
https://github.com/GoogleCloudPlatform/heapster
cluster/juju/charms/trusty/kubernetes-master/requirements.txt
0 → 100644
View file @
dddf414c
flake8
pytest
bundletester
path.py
charmhelpers
cluster/juju/charms/trusty/kubernetes-master/unit_tests/kubernetes_installer_test.py
0 → 100644
View file @
dddf414c
from
mock
import
patch
from
path
import
path
from
path
import
Path
import
pytest
import
subprocess
import
sys
# Add the hooks directory to the python path.
hooks_dir
=
Path
(
'__file__'
)
.
parent
.
abspath
()
/
'hooks'
sys
.
path
.
insert
(
0
,
hooks_dir
.
abspath
())
# Import the module to be tested.
import
kubernetes_installer
def
test_run
():
""" Test the run method both with valid commands and invalid commands. """
ls
=
'ls -l {0}/kubernetes_installer.py'
.
format
(
hooks_dir
)
output
=
kubernetes_installer
.
run
(
ls
,
False
)
assert
output
assert
'kubernetes_installer.py'
in
output
output
=
kubernetes_installer
.
run
(
ls
,
True
)
assert
output
assert
'kubernetes_installer.py'
in
output
invalid_directory
=
path
(
'/not/a/real/directory'
)
assert
not
invalid_directory
.
exists
()
invalid_command
=
'ls {0}'
.
format
(
invalid_directory
)
with
pytest
.
raises
(
subprocess
.
CalledProcessError
)
as
error
:
kubernetes_installer
.
run
(
invalid_command
)
print
(
error
)
with
pytest
.
raises
(
subprocess
.
CalledProcessError
)
as
error
:
kubernetes_installer
.
run
(
invalid_command
,
shell
=
True
)
print
(
error
)
class
TestKubernetesInstaller
():
def
makeone
(
self
,
*
args
,
**
kw
):
""" Create the KubernetesInstaller object and return it. """
from
kubernetes_installer
import
KubernetesInstaller
return
KubernetesInstaller
(
*
args
,
**
kw
)
def
test_init
(
self
):
""" Test that the init method correctly assigns the variables. """
ki
=
self
.
makeone
(
'i386'
,
'3.0.1'
,
'/tmp/does_not_exist'
)
assert
ki
.
aliases
assert
'kube-apiserver'
in
ki
.
aliases
assert
'kube-controller-manager'
in
ki
.
aliases
assert
'kube-scheduler'
in
ki
.
aliases
assert
'kubectl'
in
ki
.
aliases
assert
'kubelet'
in
ki
.
aliases
assert
ki
.
arch
==
'i386'
assert
ki
.
version
==
'3.0.1'
assert
ki
.
output_dir
==
path
(
'/tmp/does_not_exist'
)
@patch
(
'kubernetes_installer.run'
)
@patch
(
'kubernetes_installer.subprocess.call'
)
def
test_build
(
self
,
cmock
,
rmock
):
""" Test the build method with master and non-master branches. """
directory
=
path
(
'/tmp/kubernetes_installer_test/build'
)
ki
=
self
.
makeone
(
'amd64'
,
'v99.00.11'
,
directory
)
assert
not
directory
.
exists
(),
'The
%
s directory exists!'
%
directory
# Call the build method with "master" branch.
ki
.
build
(
"master"
)
# TODO: run is called many times but mock only remembers last one.
rmock
.
assert_called_with
(
'git reset --hard origin/master'
)
# TODO: call is complex and hard to verify with mock, fix that.
cmock
.
assert_called_once
()
# Call the build method with something other than "master" branch.
ki
.
build
(
"branch"
)
# TODO: run is called many times, but mock only remembers last one.
rmock
.
assert_called_with
(
'git checkout -b v99.00.11 branch'
)
# TODO: call is complex and hard to verify with mock, fix that.
cmock
.
assert_called_once
()
directory
.
rmtree_p
()
def
test_install
(
self
):
""" Test the install method that it creates the correct links. """
directory
=
path
(
'/tmp/kubernetes_installer_test/install'
)
ki
=
self
.
makeone
(
'ppc64le'
,
'1.2.3'
,
directory
)
assert
not
directory
.
exists
(),
'The
%
s directory exits!'
%
directory
directory
.
makedirs_p
()
# Create the files for the install method to link to.
(
directory
/
'kube-apiserver'
)
.
touch
()
(
directory
/
'kube-controller-manager'
)
.
touch
()
(
directory
/
'kube-proxy'
)
.
touch
()
(
directory
/
'kube-scheduler'
)
.
touch
()
(
directory
/
'kubectl'
)
.
touch
()
(
directory
/
'kubelet'
)
.
touch
()
results
=
directory
/
'install/results/go/here'
assert
not
results
.
exists
()
ki
.
install
(
results
)
assert
results
.
isdir
()
# Check that all the files were correctly aliased and are links.
assert
(
results
/
'apiserver'
)
.
islink
()
assert
(
results
/
'controller-manager'
)
.
islink
()
assert
(
results
/
'kube-proxy'
)
.
islink
()
assert
(
results
/
'scheduler'
)
.
islink
()
assert
(
results
/
'kubectl'
)
.
islink
()
assert
(
results
/
'kubelet'
)
.
islink
()
directory
.
rmtree_p
()
cluster/juju/charms/trusty/kubernetes-master/unit_tests/test_install.py
0 → 100644
View file @
dddf414c
from
mock
import
patch
,
Mock
,
MagicMock
from
path
import
Path
import
pytest
import
sys
# Munge the python path so we can find our hook code
d
=
Path
(
'__file__'
)
.
parent
.
abspath
()
/
'hooks'
sys
.
path
.
insert
(
0
,
d
.
abspath
())
# Import the modules from the hook
import
install
class
TestInstallHook
():
@patch
(
'install.path'
)
def
test_update_rc_files
(
self
,
pmock
):
"""
Test happy path on updating env files. Assuming everything
exists and is in place.
"""
pmock
.
return_value
.
lines
.
return_value
=
[
'line1'
,
'line2'
]
install
.
update_rc_files
([
'test1'
,
'test2'
])
pmock
.
return_value
.
write_lines
.
assert_called_with
([
'line1'
,
'line2'
,
'test1'
,
'test2'
])
def
test_update_rc_files_with_nonexistant_path
(
self
):
"""
Test an unhappy path if the bashrc/users do not exist.
"""
with
pytest
.
raises
(
OSError
)
as
exinfo
:
install
.
update_rc_files
([
'test1'
,
'test2'
])
@patch
(
'install.fetch'
)
@patch
(
'install.hookenv'
)
def
test_package_installation
(
self
,
hemock
,
ftmock
):
"""
Verify we are calling the known essentials to build and syndicate
kubes.
"""
pkgs
=
[
'build-essential'
,
'git'
,
'make'
,
'nginx'
,
'python-pip'
]
install
.
install_packages
()
hemock
.
log
.
assert_called_with
(
'Installing Debian packages'
)
ftmock
.
filter_installed_packages
.
assert_called_with
(
pkgs
)
@patch
(
'install.archiveurl.ArchiveUrlFetchHandler'
)
def
test_go_download
(
self
,
aumock
):
"""
Test that we are actually handing off to charm-helpers to
download a specific archive of Go. This is non-configurable so
its reasonably safe to assume we're going to always do this,
and when it changes we shall curse the brittleness of this test.
"""
ins_mock
=
aumock
.
return_value
.
install
install
.
download_go
()
url
=
'https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz'
sha1
=
'5020af94b52b65cc9b6f11d50a67e4bae07b0aff'
ins_mock
.
assert_called_with
(
url
,
'/usr/local'
,
sha1
,
'sha1'
)
@patch
(
'install.subprocess'
)
def
test_clone_repository
(
self
,
spmock
):
"""
We're not using a unit-tested git library - so ensure our subprocess
call is consistent. If we change this, we want to know we've broken it.
"""
install
.
clone_repository
()
repo
=
'https://github.com/GoogleCloudPlatform/kubernetes.git'
direct
=
'/opt/kubernetes'
spmock
.
check_output
.
assert_called_with
([
'git'
,
'clone'
,
repo
,
direct
])
@patch
(
'install.install_packages'
)
@patch
(
'install.download_go'
)
@patch
(
'install.clone_repository'
)
@patch
(
'install.update_rc_files'
)
@patch
(
'install.hookenv'
)
def
test_install_main
(
self
,
hemock
,
urmock
,
crmock
,
dgmock
,
ipmock
):
"""
Ensure the driver/main method is calling all the supporting methods.
"""
strings
=
[
'export GOROOT=/usr/local/go
\n
'
,
'export PATH=$PATH:$GOROOT/bin
\n
'
,
'export KUBE_MASTER_IP=0.0.0.0
\n
'
,
'export KUBERNETES_MASTER=http://$KUBE_MASTER_IP
\n
'
,
]
install
.
install
()
crmock
.
assert_called_once
()
dgmock
.
assert_called_once
()
crmock
.
assert_called_once
()
urmock
.
assert_called_with
(
strings
)
hemock
.
open_port
.
assert_called_with
(
8080
)
cluster/juju/charms/trusty/kubernetes/.bzrignore
0 → 100644
View file @
dddf414c
.git
cluster/juju/charms/trusty/kubernetes/.gitignore
0 → 100644
View file @
dddf414c
.bzr
*.pyc
*~
*\#*
/files/.kubernetes-*
.venv
cluster/juju/charms/trusty/kubernetes/.vendor-rc
0 → 100644
View file @
dddf414c
omit:
- .git
- .gitignore
- .gitmodules
- revision
cluster/juju/charms/trusty/kubernetes/Makefile
0 → 100644
View file @
dddf414c
build
:
virtualenv lint test
virtualenv
:
virtualenv .venv
.venv/bin/pip
install
-q
-r
requirements.txt
lint
:
virtualenv
@
.venv/bin/flake8 hooks unit_tests
--exclude
=
charmhelpers
@
.venv/bin/charm proof
test
:
virtualenv
@
CHARM_DIR
=
.
PYTHONPATH
=
./hooks .venv/bin/py.test unit_tests/
*
functional-test
:
@
bundletester
release
:
check-path virtualenv
@
.venv/bin/pip
install
git-vendor
@
.venv/bin/git-vendor
sync
-d
${
KUBERNETES_BZR
}
check-path
:
ifndef
KUBERNETES_BZR
$(error
KUBERNETES_BZR
is
undefined)
endif
clean
:
rm
-rf
.venv
find
-name
*
.pyc
-delete
cluster/juju/charms/trusty/kubernetes/README.md
0 → 100644
View file @
dddf414c
# Kubernetes Minion Charm
[
Kubernetes
](
https://github.com/googlecloudplatform/kubernetes
)
is an open
source system for managing containerized applications across multiple hosts.
Kubernetes uses
[
Docker
](
http://www.docker.io/
)
to package, instantiate and run
containerized applications.
The Kubernetes Juju charms enable you to run Kubernetes on all the cloud
platforms that Juju supports.
A Kubernetes deployment consists of several independent charms that can be
scaled to meet your needs
### Etcd
Etcd is a key value store for Kubernetes. All persistent master state
is stored in
`etcd`
.
### Flannel-docker
Flannel is a
[
software defined networking
](
http://en.wikipedia.org/wiki/Software-defined_networking
)
component that provides individual subnets for each machine in the cluster.
### Docker
Docker is an open platform for distributing applications for system administrators.
### Kubernetes master
The controlling unit in a Kubernetes cluster is called the master. It is the
main management contact point providing many management services for the worker
nodes.
### Kubernetes minion
The servers that perform the work are known as minions. Minions must be able to
communicate with the master and run the workloads that are assigned to them.
## Usage
#### Deploying the Development Focus
To deploy a Kubernetes environment in Juju :
juju deploy cs:~kubernetes/trusty/etcd
juju deploy cs:trusty/flannel-docker
juju deploy cs:trusty/docker
juju deploy local:trusty/kubernetes-master
juju deploy local:trusty/kubernetes
juju add-relation etcd flannel-docker
juju add-relation flannel-docker:network docker:network
juju add-relation flannel-docker:docker-host docker
juju add-relation etcd kubernetes
juju add-relation etcd kubernetes-master
juju add-relation kubernetes kubernetes-master
#### Deploying the recommended configuration
A bundle can be used to deploy Kubernetes onto any cloud it can be
orchestrated directly in the Juju Graphical User Interface, when using
`juju quickstart`
:
juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml
For more information on the recommended bundle deployment, see the
[
Kubernetes bundle documentation
](
https://github.com/whitmo/bundle-kubernetes
)
#### Post Deployment
To interact with the kubernetes environment, either build or
[
download
](
https://github.com/GoogleCloudPlatform/kubernetes/releases
)
the
[
kubectl
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
binary (available in the releases binary tarball) and point it to the master with :
$ juju status kubernetes-master | grep public
public-address: 104.131.108.99
$ export KUBERNETES_MASTER="104.131.108.99"
# Configuration
For you convenience this charm supports changing the version of kubernetes binaries.
This can be done through the Juju GUI or on the command line:
juju set kubernetes version=”v0.10.0”
If the charm does not already contain the tar file with the desired architecture
and version it will attempt to download the kubernetes binaries using the gsutil
command.
Congratulations you know have deployed a Kubernetes environment! Use the
[
kubectl
](
https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md
)
to interact with the environment.
# Kubernetes information
-
[
Kubernetes github project
](
https://github.com/GoogleCloudPlatform/kubernetes
)
-
[
Kubernetes issue tracker
](
https://github.com/GoogleCloudPlatform/kubernetes/issues
)
-
[
Kubernetes Documenation
](
https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs
)
-
[
Kubernetes releases
](
https://github.com/GoogleCloudPlatform/kubernetes/releases
)
cluster/juju/charms/trusty/kubernetes/copyright
0 → 100644
View file @
dddf414c
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl
0 → 100644
View file @
dddf414c
description "cadvisor container metrics"
start on started docker
stop on stopping docker
limit nofile 20000 20000
kill timeout 60 # wait 60s between SIGTERM and SIGKILL.
exec docker run \
--volume=/var/run:/var/run:rw \
--volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=127.0.0.1:4193:8080 \
--name=cadvisor \
google/cadvisor:latest
cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl
0 → 100644
View file @
dddf414c
description "kubernetes kubelet"
start on runlevel [2345]
stop on runlevel [!2345]
limit nofile 20000 20000
kill timeout 60 # wait 60s between SIGTERM and SIGKILL.
exec /usr/local/bin/kubelet \
--address=%(kubelet_bind_addr)s \
--api_servers=%(kubeapi_server)s \
--hostname_override=%(kubelet_bind_addr)s \
--cadvisor_port=4193 \
--logtostderr=true
cluster/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl
0 → 100644
View file @
dddf414c
description "kubernetes proxy"
start on runlevel [2345]
stop on runlevel [!2345]
limit nofile 20000 20000
kill timeout 60 # wait 60s between SIGTERM and SIGKILL.
exec /usr/local/bin/proxy \
--master=%(kubeapi_server)s \
--logtostderr=true
cluster/juju/charms/trusty/kubernetes/hooks/api-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes/hooks/etcd-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes/hooks/hooks.py
0 → 100755
View file @
dddf414c
#!/usr/bin/python
"""
The main hook file that is called by Juju.
"""
import
json
import
httplib
import
os
import
time
import
socket
import
subprocess
import
sys
import
urlparse
from
charmhelpers.core
import
hookenv
,
host
from
kubernetes_installer
import
KubernetesInstaller
from
path
import
path
from
lib.registrator
import
Registrator
hooks
=
hookenv
.
Hooks
()
@hooks.hook
(
'api-relation-changed'
)
def
api_relation_changed
():
"""
On the relation to the api server, this function determines the appropriate
architecture and the configured version to copy the kubernetes binary files
from the kubernetes-master charm and installs it locally on this machine.
"""
hookenv
.
log
(
'Starting api-relation-changed'
)
charm_dir
=
path
(
hookenv
.
charm_dir
())
# Get the package architecture, rather than the from the kernel (uname -m).
arch
=
subprocess
.
check_output
([
'dpkg'
,
'--print-architecture'
])
.
strip
()
kubernetes_bin_dir
=
path
(
'/opt/kubernetes/bin'
)
# Get the version of kubernetes to install.
version
=
subprocess
.
check_output
([
'relation-get'
,
'version'
])
.
strip
()
print
(
'Relation version: '
,
version
)
if
not
version
:
print
(
'No version present in the relation.'
)
exit
(
0
)
version_file
=
charm_dir
/
'.version'
if
version_file
.
exists
():
previous_version
=
version_file
.
text
()
print
(
'Previous version: '
,
previous_version
)
if
version
==
previous_version
:
exit
(
0
)
# Can not download binaries while the service is running, so stop it.
# TODO: Figure out a better way to handle upgraded kubernetes binaries.
for
service
in
(
'kubelet'
,
'proxy'
):
if
host
.
service_running
(
service
):
host
.
service_stop
(
service
)
command
=
[
'relation-get'
,
'private-address'
]
# Get the kubernetes-master address.
server
=
subprocess
.
check_output
(
command
)
.
strip
()
print
(
'Kubernetes master private address: '
,
server
)
installer
=
KubernetesInstaller
(
arch
,
version
,
server
,
kubernetes_bin_dir
)
installer
.
download
()
installer
.
install
()
# Write the most recently installed version number to the file.
version_file
.
write_text
(
version
)
relation_changed
()
@hooks.hook
(
'etcd-relation-changed'
,
'network-relation-changed'
)
def
relation_changed
():
"""Connect the parts and go :-)
"""
template_data
=
get_template_data
()
# Check required keys
for
k
in
(
'etcd_servers'
,
'kubeapi_server'
):
if
not
template_data
.
get
(
k
):
print
(
'Missing data for
%
s
%
s'
%
(
k
,
template_data
))
return
print
(
'Running with
\n
%
s'
%
template_data
)
# Setup kubernetes supplemental group
setup_kubernetes_group
()
# Register upstart managed services
for
n
in
(
'kubelet'
,
'proxy'
):
if
render_upstart
(
n
,
template_data
)
or
not
host
.
service_running
(
n
):
print
(
'Starting
%
s'
%
n
)
host
.
service_restart
(
n
)
# Register machine via api
print
(
'Registering machine'
)
register_machine
(
template_data
[
'kubeapi_server'
])
# Save the marker (for restarts to detect prev install)
template_data
.
save
()
def
get_template_data
():
rels
=
hookenv
.
relations
()
template_data
=
hookenv
.
Config
()
template_data
.
CONFIG_FILE_NAME
=
'.unit-state'
overlay_type
=
get_scoped_rel_attr
(
'network'
,
rels
,
'overlay_type'
)
etcd_servers
=
get_rel_hosts
(
'etcd'
,
rels
,
(
'hostname'
,
'port'
))
api_servers
=
get_rel_hosts
(
'api'
,
rels
,
(
'hostname'
,
'port'
))
# kubernetes master isn't ha yet.
if
api_servers
:
api_info
=
api_servers
.
pop
()
api_servers
=
'http://
%
s:
%
s'
%
(
api_info
[
0
],
api_info
[
1
])
template_data
[
'overlay_type'
]
=
overlay_type
template_data
[
'kubelet_bind_addr'
]
=
_bind_addr
(
hookenv
.
unit_private_ip
())
template_data
[
'proxy_bind_addr'
]
=
_bind_addr
(
hookenv
.
unit_get
(
'public-address'
))
template_data
[
'kubeapi_server'
]
=
api_servers
template_data
[
'etcd_servers'
]
=
','
.
join
([
'http://
%
s:
%
s'
%
(
s
[
0
],
s
[
1
])
for
s
in
sorted
(
etcd_servers
)])
template_data
[
'identifier'
]
=
os
.
environ
[
'JUJU_UNIT_NAME'
]
.
replace
(
'/'
,
'-'
)
return
_encode
(
template_data
)
def
_bind_addr
(
addr
):
if
addr
.
replace
(
'.'
,
''
)
.
isdigit
():
return
addr
try
:
return
socket
.
gethostbyname
(
addr
)
except
socket
.
error
:
raise
ValueError
(
'Could not resolve private address'
)
def
_encode
(
d
):
for
k
,
v
in
d
.
items
():
if
isinstance
(
v
,
unicode
):
d
[
k
]
=
v
.
encode
(
'utf8'
)
return
d
def
get_scoped_rel_attr
(
rel_name
,
rels
,
attr
):
private_ip
=
hookenv
.
unit_private_ip
()
for
r
,
data
in
rels
.
get
(
rel_name
,
{})
.
items
():
for
unit_id
,
unit_data
in
data
.
items
():
if
unit_data
.
get
(
'private-address'
)
!=
private_ip
:
continue
if
unit_data
.
get
(
attr
):
return
unit_data
.
get
(
attr
)
def
get_rel_hosts
(
rel_name
,
rels
,
keys
=
(
'private-address'
,)):
hosts
=
[]
for
r
,
data
in
rels
.
get
(
rel_name
,
{})
.
items
():
for
unit_id
,
unit_data
in
data
.
items
():
if
unit_id
==
hookenv
.
local_unit
():
continue
values
=
[
unit_data
.
get
(
k
)
for
k
in
keys
]
if
not
all
(
values
):
continue
hosts
.
append
(
len
(
values
)
==
1
and
values
[
0
]
or
values
)
return
hosts
def
render_upstart
(
name
,
data
):
tmpl_path
=
os
.
path
.
join
(
os
.
environ
.
get
(
'CHARM_DIR'
),
'files'
,
'
%
s.upstart.tmpl'
%
name
)
with
open
(
tmpl_path
)
as
fh
:
tmpl
=
fh
.
read
()
rendered
=
tmpl
%
data
tgt_path
=
'/etc/init/
%
s.conf'
%
name
if
os
.
path
.
exists
(
tgt_path
):
with
open
(
tgt_path
)
as
fh
:
contents
=
fh
.
read
()
if
contents
==
rendered
:
return
False
with
open
(
tgt_path
,
'w'
)
as
fh
:
fh
.
write
(
rendered
)
return
True
def
register_machine
(
apiserver
,
retry
=
False
):
parsed
=
urlparse
.
urlparse
(
apiserver
)
# identity = hookenv.local_unit().replace('/', '-')
private_address
=
hookenv
.
unit_private_ip
()
with
open
(
'/proc/meminfo'
)
as
fh
:
info
=
fh
.
readline
()
mem
=
info
.
strip
()
.
split
(
':'
)[
1
]
.
strip
()
.
split
()[
0
]
cpus
=
os
.
sysconf
(
'SC_NPROCESSORS_ONLN'
)
registration_request
=
Registrator
()
registration_request
.
data
[
'Kind'
]
=
'Minion'
registration_request
.
data
[
'id'
]
=
private_address
registration_request
.
data
[
'name'
]
=
private_address
registration_request
.
data
[
'metadata'
][
'name'
]
=
private_address
registration_request
.
data
[
'spec'
][
'capacity'
][
'mem'
]
=
mem
+
' K'
registration_request
.
data
[
'spec'
][
'capacity'
][
'cpu'
]
=
cpus
registration_request
.
data
[
'spec'
][
'externalID'
]
=
private_address
registration_request
.
data
[
'status'
][
'hostIP'
]
=
private_address
response
,
result
=
registration_request
.
register
(
parsed
.
hostname
,
parsed
.
port
,
'/api/v1beta3/nodes'
)
print
(
response
)
try
:
registration_request
.
command_succeeded
(
response
,
result
)
except
ValueError
:
# This happens when we have already registered
# for now this is OK
pass
def
setup_kubernetes_group
():
output
=
subprocess
.
check_output
([
'groups'
,
'kubernetes'
])
# TODO: check group exists
if
'docker'
not
in
output
:
subprocess
.
check_output
(
[
'usermod'
,
'-a'
,
'-G'
,
'docker'
,
'kubernetes'
])
if
__name__
==
'__main__'
:
hooks
.
execute
(
sys
.
argv
)
cluster/juju/charms/trusty/kubernetes/hooks/install
0 → 100755
View file @
dddf414c
#!/bin/bash
set
-ex
# Install is guaranteed to run once per rootfs
echo
"Installing kubernetes-node on
$JUJU_UNIT_NAME
"
apt-get update
-qq
apt-get
install
-q
-y
\
bridge-utils
\
python-dev
\
python-pip
\
wget
pip
install
path.py
# Create the necessary kubernetes group.
groupadd kubernetes
useradd
-d
/var/lib/kubernetes
\
-g
kubernetes
\
-s
/sbin/nologin
\
--system
\
kubernetes
install
-d
-m
0744
-o
kubernetes
-g
kubernetes /var/lib/kubernetes
install
-d
-m
0744
-o
kubernetes
-g
kubernetes /etc/kubernetes/manifests
# wait for the world, depends on where we installed it from distro
#sudo service docker.io stop
# or upstream archive
#sudo service docker stop
cluster/juju/charms/trusty/kubernetes/hooks/kubernetes_installer.py
0 → 100644
View file @
dddf414c
import
subprocess
from
path
import
path
class
KubernetesInstaller
():
"""
This class contains the logic needed to install kuberentes binary files.
"""
def
__init__
(
self
,
arch
,
version
,
master
,
output_dir
):
""" Gather the required variables for the install. """
# The kubernetes charm needs certain commands to be aliased.
self
.
aliases
=
{
'kube-proxy'
:
'proxy'
,
'kubelet'
:
'kubelet'
}
self
.
arch
=
arch
self
.
version
=
version
self
.
master
=
master
self
.
output_dir
=
output_dir
def
download
(
self
):
""" Download the kuberentes binaries from the kubernetes master. """
url
=
'http://{0}/kubernetes/{1}/local/bin/linux/{2}'
.
format
(
self
.
master
,
self
.
version
,
self
.
arch
)
if
not
self
.
output_dir
.
isdir
():
self
.
output_dir
.
makedirs_p
()
for
key
in
self
.
aliases
:
uri
=
'{0}/{1}'
.
format
(
url
,
key
)
destination
=
self
.
output_dir
/
key
wget
=
'wget -nv {0} -O {1}'
.
format
(
uri
,
destination
)
print
(
wget
)
output
=
subprocess
.
check_output
(
wget
.
split
())
print
(
output
)
destination
.
chmod
(
0
o755
)
def
install
(
self
,
install_dir
=
path
(
'/usr/local/bin'
)):
""" Create links to the binary files to the install directory. """
if
not
install_dir
.
isdir
():
install_dir
.
makedirs_p
()
# Create the symbolic links to the real kubernetes binaries.
for
key
,
value
in
self
.
aliases
.
iteritems
():
target
=
self
.
output_dir
/
key
if
target
.
exists
():
link
=
install_dir
/
value
if
link
.
exists
():
link
.
remove
()
target
.
symlink
(
link
)
else
:
print
(
'Error target file {0} does not exist.'
.
format
(
target
))
exit
(
1
)
cluster/juju/charms/trusty/kubernetes/hooks/lib/__init__.py
0 → 100644
View file @
dddf414c
cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py
0 → 100644
View file @
dddf414c
import
httplib
import
json
import
time
class
Registrator
:
def
__init__
(
self
):
self
.
ds
=
{
"creationTimestamp"
:
""
,
"kind"
:
"Minion"
,
"name"
:
""
,
# private_address
"metadata"
:
{
"name"
:
""
,
#private_address,
},
"spec"
:
{
"externalID"
:
""
,
#private_address
"capacity"
:
{
"mem"
:
""
,
# mem + ' K',
"cpu"
:
""
,
# cpus
}
},
"status"
:
{
"conditions"
:
[],
"hostIP"
:
""
,
#private_address
}
}
@property
def
data
(
self
):
''' Returns a data-structure for population to make a request. '''
return
self
.
ds
def
register
(
self
,
hostname
,
port
,
api_path
):
''' Contact the API Server for a new registration '''
headers
=
{
"Content-type"
:
"application/json"
,
"Accept"
:
"application/json"
}
connection
=
httplib
.
HTTPConnection
(
hostname
,
port
)
print
'CONN {}'
.
format
(
connection
)
connection
.
request
(
"POST"
,
api_path
,
json
.
dumps
(
self
.
data
),
headers
)
response
=
connection
.
getresponse
()
body
=
response
.
read
()
print
(
body
)
result
=
json
.
loads
(
body
)
print
(
"Response status:
%
s reason:
%
s body:
%
s"
%
\
(
response
.
status
,
response
.
reason
,
result
))
return
response
,
result
def
update
(
self
):
''' Contact the API Server to update a registration '''
# do a get on the API for the node
# repost to the API with any modified data
pass
def
save
(
self
):
''' Marshall the registration data '''
# TODO
pass
def
command_succeeded
(
self
,
response
,
result
):
''' Evaluate response data to determine if the command was successful '''
if
response
.
status
in
[
200
,
201
]:
print
(
"Registered"
)
return
True
elif
response
.
status
in
[
409
,]:
print
(
"Status Conflict"
)
# Suggested return a PUT instead of a POST with this response
# code, this predicates use of the UPDATE method
# TODO
elif
response
.
status
in
(
500
,)
and
result
.
get
(
'message'
,
''
)
.
startswith
(
'The requested resource does not exist'
):
# There's something fishy in the kube api here (0.4 dev), first time we
# go to register a new minion, we always seem to get this error.
# https://github.com/GoogleCloudPlatform/kubernetes/issues/1995
time
.
sleep
(
1
)
print
(
"Retrying registration..."
)
raise
ValueError
(
"Registration returned 500, retry"
)
# return register_machine(apiserver, retry=True)
else
:
print
(
"Registration error"
)
# TODO - get request data
raise
RuntimeError
(
"Unable to register machine with"
)
cluster/juju/charms/trusty/kubernetes/hooks/network-relation-changed
0 → 120000
View file @
dddf414c
hooks.py
\ No newline at end of file
cluster/juju/charms/trusty/kubernetes/hooks/start
0 → 100755
View file @
dddf414c
#!/bin/bash
set
-ex
# Start is guaranteed to be called once when after the unit is installed
# *AND* once everytime a machine is rebooted.
if
[
!
-f
$CHARM_DIR
/.unit-state
]
then
exit
0
;
fi
service docker restart
service proxy restart
service kubelet restart
cluster/juju/charms/trusty/kubernetes/icon.svg
0 → 100644
View file @
dddf414c
This diff is collapsed.
Click to expand it.
cluster/juju/charms/trusty/kubernetes/metadata.yaml
0 → 100644
View file @
dddf414c
name
:
kubernetes
summary
:
Container Cluster Management Node
maintainers
:
-
Matt Bruzek <matthew.bruzek@canonical.com>
-
Whit Morriss <whit.morriss@canonical.com>
-
Charles Butler <charles.butler@canonical.com>
description
:
|
Provides a kubernetes node for running containers
See http://goo.gl/CSggxE
tags
:
-
ops
-
network
subordinate
:
true
requires
:
etcd
:
interface
:
etcd
api
:
interface
:
kubernetes-api
network
:
interface
:
overlay-network
docker-host
:
interface
:
juju-info
scope
:
container
cluster/juju/charms/trusty/kubernetes/requirements.txt
0 → 100644
View file @
dddf414c
flake8
pytest
bundletester
path.py
cluster/juju/charms/trusty/kubernetes/unit_tests/lib/test_registrator.py
0 → 100644
View file @
dddf414c
import
json
from
mock
import
MagicMock
,
patch
,
call
from
path
import
Path
import
pytest
import
sys
d
=
Path
(
'__file__'
)
.
parent
.
abspath
()
/
'hooks'
sys
.
path
.
insert
(
0
,
d
.
abspath
())
from
lib.registrator
import
Registrator
class
TestRegistrator
():
def
setup_method
(
self
,
method
):
self
.
r
=
Registrator
()
def
test_data_type
(
self
):
if
type
(
self
.
r
.
data
)
is
not
dict
:
pytest
.
fail
(
"Invalid type"
)
@patch
(
'json.loads'
)
@patch
(
'httplib.HTTPConnection'
)
def
test_register
(
self
,
httplibmock
,
jsonmock
):
result
=
self
.
r
.
register
(
'foo'
,
80
,
'/v1beta1/test'
)
httplibmock
.
assert_called_with
(
'foo'
,
80
)
requestmock
=
httplibmock
()
.
request
requestmock
.
assert_called_with
(
"POST"
,
"/v1beta1/test"
,
json
.
dumps
(
self
.
r
.
data
),
{
"Content-type"
:
"application/json"
,
"Accept"
:
"application/json"
})
def
test_command_succeeded
(
self
):
response
=
MagicMock
()
result
=
json
.
loads
(
'{"status": "Failure", "kind": "Status", "code": 409, "apiVersion": "v1beta2", "reason": "AlreadyExists", "details": {"kind": "minion", "id": "10.200.147.200"}, "message": "minion
\\
"10.200.147.200
\\
" already exists", "creationTimestamp": null}'
)
response
.
status
=
200
self
.
r
.
command_succeeded
(
response
,
result
)
response
.
status
=
500
with
pytest
.
raises
(
RuntimeError
):
self
.
r
.
command_succeeded
(
response
,
result
)
response
.
status
=
409
with
pytest
.
raises
(
ValueError
):
self
.
r
.
command_succeeded
(
response
,
result
)
cluster/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py
0 → 100644
View file @
dddf414c
# import pytest
class
TestHooks
():
# TODO: Actually write tests.
def
test_fake
(
self
):
pass
cluster/juju/prereqs/ubuntu-juju.sh
View file @
dddf414c
...
@@ -20,12 +20,12 @@ set -o nounset
...
@@ -20,12 +20,12 @@ set -o nounset
set
-o
pipefail
set
-o
pipefail
function
check_for_ppa
(){
function
check_for_ppa
()
{
local
repo
=
"
$1
"
local
repo
=
"
$1
"
grep
-qsw
$repo
/etc
c
/apt/sources.list /etc/apt/sources.list.d/
*
grep
-qsw
$repo
/etc/apt/sources.list /etc/apt/sources.list.d/
*
}
}
function
package_status
(){
function
package_status
()
{
local
pkgname
=
$1
local
pkgname
=
$1
local
pkgstatus
local
pkgstatus
pkgstatus
=
$(
dpkg-query
-W
--showformat
=
'${Status}\n'
"
${
pkgname
}
"
)
pkgstatus
=
$(
dpkg-query
-W
--showformat
=
'${Status}\n'
"
${
pkgname
}
"
)
...
@@ -33,10 +33,9 @@ function package_status(){
...
@@ -33,10 +33,9 @@ function package_status(){
echo
"Missing package
${
pkgname
}
"
echo
"Missing package
${
pkgname
}
"
sudo
apt-get
--force-yes
--yes
install
${
pkgname
}
sudo
apt-get
--force-yes
--yes
install
${
pkgname
}
fi
fi
}
}
function
gather_installation_reqs
(){
function
gather_installation_reqs
()
{
if
!
check_for_ppa
"juju"
;
then
if
!
check_for_ppa
"juju"
;
then
echo
"... Detected missing dependencies.. running"
echo
"... Detected missing dependencies.. running"
echo
"... add-apt-repository ppa:juju/stable"
echo
"... add-apt-repository ppa:juju/stable"
...
@@ -45,5 +44,5 @@ function gather_installation_reqs(){
...
@@ -45,5 +44,5 @@ function gather_installation_reqs(){
fi
fi
package_status
'juju-quickstart'
package_status
'juju-quickstart'
package_status
'juju-deployer'
}
}
cluster/juju/return-node-ips.py
0 → 100755
View file @
dddf414c
#!/usr/bin/env python
import
json
import
sys
# This script helps parse out the private IP addreses from the
# `juju run` command's JSON object, see cluster/juju/util.sh
if
len
(
sys
.
argv
)
>
1
:
# It takes the JSON output as the first argument.
nodes
=
json
.
loads
(
sys
.
argv
[
1
])
# There can be multiple nodes to print the Stdout.
for
num
in
nodes
:
print
num
[
'Stdout'
]
.
rstrip
()
else
:
exit
(
1
)
cluster/juju/util.sh
View file @
dddf414c
...
@@ -19,8 +19,13 @@ set -o errexit
...
@@ -19,8 +19,13 @@ set -o errexit
set
-o
nounset
set
-o
nounset
set
-o
pipefail
set
-o
pipefail
source
$KUBE_ROOT
/cluster/juju/prereqs/ubuntu-juju.sh
UTIL_SCRIPT
=
$(
readlink
-m
"
${
BASH_SOURCE
}
"
)
KUBE_BUNDLE_URL
=
'https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml'
JUJU_PATH
=
$(
dirname
${
UTIL_SCRIPT
})
source
${
JUJU_PATH
}
/prereqs/ubuntu-juju.sh
export
JUJU_REPOSITORY
=
${
JUJU_PATH
}
/charms
#KUBE_BUNDLE_URL='https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml'
KUBE_BUNDLE_PATH
=
${
JUJU_PATH
}
/bundles/local.yaml
function
verify-prereqs
()
{
function
verify-prereqs
()
{
gather_installation_reqs
gather_installation_reqs
}
}
...
@@ -30,66 +35,67 @@ function get-password() {
...
@@ -30,66 +35,67 @@ function get-password() {
}
}
function
kube-up
()
{
function
kube-up
()
{
# If something were to happen that I'm not accounting for, do not
if
[[
-d
"~/.juju/current-env"
]]
;
then
# punish the user by making them tear things down. In a perfect world
juju quickstart
-i
--no-browser
# quickstart should handle this situation, so be nice in the meantime
else
local
envstatus
juju quickstart
--no-browser
envstatus
=
$(
juju status kubernetes-master
--format
=
oneline
)
if
[[
""
==
"
${
envstatus
}
"
]]
;
then
if
[[
-d
"~/.juju/current-env"
]]
;
then
juju quickstart
-i
--no-browser
-i
$KUBE_BUNDLE_URL
else
juju quickstart
--no-browser
${
KUBE_BUNDLE_URL
}
fi
sleep
60
fi
fi
# The juju-deployer command will deploy the bundle and can be run
# multiple times to continue deploying the parts that fail.
juju deployer
-c
${
KUBE_BUNDLE_PATH
}
# Sleep due to juju bug http://pad.lv/1432759
# Sleep due to juju bug http://pad.lv/1432759
sleep-status
sleep-status
detect-master
detect-minions
}
}
function
kube-down
()
{
local
jujuenv
jujuenv
=
$(
cat
~/.juju/current-environment
)
juju destroy-environment
$jujuenv
}
function
detect-master
()
{
function
detect-master
()
{
local
kubestatus
local
kubestatus
# Capturing a newline, and my awk-fu was weak - pipe through tr -d
# Capturing a newline, and my awk-fu was weak - pipe through tr -d
kubestatus
=
$(
juju status
--format
=
oneline kubernetes-master |
awk
'{print $3}'
|
tr
-d
"
\n
"
)
kubestatus
=
$(
juju status
--format
=
oneline kubernetes-master |
awk
'{print $3}'
|
tr
-d
"
\n
"
)
export
KUBE_MASTER_IP
=
${
kubestatus
}
export
KUBE_MASTER_IP
=
${
kubestatus
}
export
KUBE_MASTER
=
$
KUBE_MASTER_IP
:8080
export
KUBE_MASTER
=
$
{
KUBE_MASTER_IP
}
export
KUBERNETES_MASTER
=
$KUBE_MASTER
export
KUBERNETES_MASTER
=
http://
${
KUBE_MASTER
}
:8080
echo
"Kubernetes master: "
${
KUBERNETES_MASTER
}
}
}
function
detect-minions
(){
function
detect-minions
()
{
# Strip out the components except for STDOUT return
# Run the Juju command that gets the minion private IP addresses.
# and trim out the single quotes to build an array of minions
local
ipoutput
ipoutput
=
$(
juju run
--service
kubernetes
"unit-get private-address"
--format
=
json
)
echo
$ipoutput
# Strip out the IP addresses
#
#
# Example Output:
# Example Output:
#- MachineId: "10"
#- MachineId: "10"
# Stdout:
'10.197.55.232
# Stdout:
|
#
'
#
10.197.55.232
# UnitId: kubernetes/0
# UnitId: kubernetes/0
# - MachineId: "11"
# - MachineId: "11"
# Stdout:
'10.202.146.124
# Stdout:
|
#
'
#
10.202.146.124
# UnitId: kubernetes/1
# UnitId: kubernetes/1
export
KUBE_MINION_IP_ADDRESSES
=(
$(${
JUJU_PATH
}
/return-node-ips.py
"
${
ipoutput
}
"
)
)
KUBE_MINION_IP_ADDRESSES
=(
$(
juju run
--service
kubernetes
\
echo
"Kubernetes minions: "
${
KUBE_MINION_IP_ADDRESSES
[@]
}
"unit-get private-address"
--format
=
yaml
\
export
NUM_MINIONS
=
${#
KUBE_MINION_IP_ADDRESSES
[@]
}
|
awk
'/Stdout/ {gsub(/'
\'
'/,""); print $2}'
)
)
export
MINION_NAMES
=
$KUBE_MINION_IP_ADDRESSES
NUM_MINIONS
=
${#
KUBE_MINION_IP_ADDRESSES
[@]
}
MINION_NAMES
=
$KUBE_MINION_IP_ADDRESSES
}
}
function
setup-logging-firewall
(){
function
setup-logging-firewall
()
{
echo
"TODO: setup logging and firewall rules"
echo
"TODO: setup logging and firewall rules"
}
}
function
teardown-logging-firewall
(){
function
teardown-logging-firewall
()
{
echo
"TODO: teardown logging and firewall rules"
echo
"TODO: teardown logging and firewall rules"
}
}
function
sleep-status
()
{
function
sleep-status
(){
local
i
local
i
local
maxtime
local
maxtime
local
jujustatus
local
jujustatus
...
@@ -97,10 +103,17 @@ function sleep-status(){
...
@@ -97,10 +103,17 @@ function sleep-status(){
maxtime
=
900
maxtime
=
900
jujustatus
=
''
jujustatus
=
''
echo
"Waiting up to 15 minutes to allow the cluster to come online... wait for it..."
echo
"Waiting up to 15 minutes to allow the cluster to come online... wait for it..."
jujustatus
=
$(
juju status kubernetes-master
--format
=
oneline
)
if
[[
$jujustatus
==
*
"started"
*
]]
;
then
return
fi
while
[[
$i
<
$maxtime
&&
$jujustatus
!=
*
"started"
*
]]
;
do
while
[[
$i
<
$maxtime
&&
$jujustatus
!=
*
"started"
*
]]
;
do
sleep
15
i+
=
15
jujustatus
=
$(
juju status kubernetes-master
--format
=
oneline
)
jujustatus
=
$(
juju status kubernetes-master
--format
=
oneline
)
sleep
30
i+
=
30
done
done
# sleep because we cannot get the status back of where the minions are in the deploy phase
# sleep because we cannot get the status back of where the minions are in the deploy phase
...
@@ -109,4 +122,3 @@ function sleep-status(){
...
@@ -109,4 +122,3 @@ function sleep-status(){
echo
"Sleeping an additional minute to allow the cluster to settle"
echo
"Sleeping an additional minute to allow the cluster to settle"
sleep
60
sleep
60
}
}
docs/getting-started-guides/juju.md
View file @
dddf414c
## Getting start with Juju
## Getting start
ed
with Juju
Juju handles provisioning machines and deploying complex systems to a
Juju handles provisioning machines and deploying complex systems to a
wide number of clouds.
wide number of clouds, supporting service orchestration once the bundle of
services has been deployed.
### Prerequisites
### Prerequisites
> Note: If you're running kube-up, on ubuntu - all of the dependencies
> will be handled for you. You may safely skip to the section:
> [Launch Kubernetes Cluster](#launch-kubernetes-cluster)
#### On Ubuntu
#### On Ubuntu
[
Install the Juju client
](
https://juju.ubuntu.com/install
)
on your
[
Install the Juju client
](
https://juju.ubuntu.com/install
)
on your
...
@@ -39,13 +44,19 @@ interface.
...
@@ -39,13 +44,19 @@ interface.
## Launch Kubernetes cluster
## Launch Kubernetes cluster
juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml
You will need to have the Kubernetes tools compiled before launching the cluster
make all WHAT=cmd/kubectl
export KUBERNETES_PROVIDER=juju
cluster/kube-up.sh
First this command will start a curses based gui allowing you to set
If this is your first time running the
`kube-up.sh`
script, it will install
up credentials and other environmental settings for several different
the required predependencies to get started with Juju, additionally it will
providers including Azure and AWS.
launch a curses based configuration utility allowing you to select your cloud
provider and enter the proper access credentials.
Next it will deploy the kubernetes master, etcd, 2 minions with flannel networking.
Next it will deploy the kubernetes master, etcd, 2 minions with flannel based
Software Defined Networking.
## Exploring the cluster
## Exploring the cluster
...
@@ -53,14 +64,15 @@ Next it will deploy the kubernetes master, etcd, 2 minions with flannel networki
...
@@ -53,14 +64,15 @@ Next it will deploy the kubernetes master, etcd, 2 minions with flannel networki
Juju status provides information about each unit in the cluster:
Juju status provides information about each unit in the cluster:
juju status --format=oneline
juju status --format=oneline
- docker/0: 52.4.92.78 (started)
- etcd/0: 52.0.74.109 (started)
- flannel-docker/0: 52.4.92.78 (started)
- flannel/0: 52.0.149.150 (started)
- kubernetes/0: 52.4.92.78 (started)
- flannel/1: 52.0.185.81 (started)
- docker/1: 52.6.104.142 (started)
- juju-gui/0: 52.1.150.81 (started)
- flannel-docker/1: 52.6.104.142 (started)
- kubernetes/0: 52.0.149.150 (started)
- kubernetes/1: 52.6.104.142 (started)
- kubernetes/1: 52.0.185.81 (started)
- etcd/0: 52.5.216.210 (started) 4001/tcp
- kubernetes-master/0: 52.1.120.142 (started)
- juju-gui/0: 52.5.205.174 (started) 80/tcp, 443/tcp
- kubernetes-master/0: 52.6.19.238 (started) 8080/tcp
You can use
`juju ssh`
to access any of the units:
You can use
`juju ssh`
to access any of the units:
...
@@ -150,8 +162,7 @@ Finally delete the pod:
...
@@ -150,8 +162,7 @@ Finally delete the pod:
We can add minion units like so:
We can add minion units like so:
juju add-unit flannel # creates unit flannel/2
juju add-unit docker # creates unit docker/2, kubernetes/2, docker-flannel/2
juju add-unit kubernetes --to flannel/2
## Tear down cluster
## Tear down cluster
...
@@ -175,6 +186,16 @@ Kubernetes Bundle on Github
...
@@ -175,6 +186,16 @@ Kubernetes Bundle on Github
Juju runs natively against a variety of cloud providers and can be
Juju runs natively against a variety of cloud providers and can be
made to work against many more using a generic manual provider.
made to work against many more using a generic manual provider.
Provider | v0.15.0
-------------- | -------
AWS | TBD
HPCloud | TBD
OpenStack | TBD
Joyent | TBD
Azure | TBD
Digital Ocean | TBD
MAAS (bare metal) | TBD
GCE | TBD
Provider | v0.8.1
Provider | v0.8.1
...
@@ -187,4 +208,3 @@ Azure | TBD
...
@@ -187,4 +208,3 @@ Azure | TBD
Digital Ocean | TBD
Digital Ocean | TBD
MAAS (bare metal) | TBD
MAAS (bare metal) | TBD
GCE | TBD
GCE | TBD
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment