Initial checkin of v1.1 -- does not build
This commit is contained in:
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
@@ -0,0 +1,289 @@
|
||||
---
|
||||
layout: docwithnav
|
||||
title: "Kubernetes on Azure with CoreOS and Weave"
|
||||
---
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
Kubernetes on Azure with CoreOS and [Weave](http://weave.works)
|
||||
---------------------------------------------------------------
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Let's go!](#lets-go)
|
||||
- [Deploying the workload](#deploying-the-workload)
|
||||
- [Scaling](#scaling)
|
||||
- [Exposing the app to the outside world](#exposing-the-app-to-the-outside-world)
|
||||
- [Next steps](#next-steps)
|
||||
- [Tear down...](#tear-down)
|
||||
|
||||
## Introduction
|
||||
|
||||
In this guide I will demonstrate how to deploy a Kubernetes cluster to Azure cloud. You will be using CoreOS with Weave, which implements simple and secure networking, in a transparent, yet robust way. The purpose of this guide is to provide an out-of-the-box implementation that can ultimately be taken into production with little change. It will demonstrate how to provision a dedicated Kubernetes master and etcd nodes, and show how to scale the cluster with ease.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. You need an Azure account.
|
||||
|
||||
## Let's go!
|
||||
|
||||
To get started, you need to checkout the code:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
git clone https://github.com/kubernetes/kubernetes
|
||||
cd kubernetes/docs/getting-started-guides/coreos/azure/
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You will need to have [Node.js installed](http://nodejs.org/download/) on you machine. If you have previously used Azure CLI, you should have it already.
|
||||
|
||||
First, you need to install some of the dependencies with
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
npm install
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Now, all you need to do is:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
./azure-login.js -u <your_username>
|
||||
./create-kubernetes-cluster.js
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
This script will provision a cluster suitable for production use, where there is a ring of 3 dedicated etcd nodes: 1 kubernetes master and 2 kubernetes nodes. The `kube-00` VM will be the master, your work loads are only to be deployed on the nodes, `kube-01` and `kube-02`. Initially, all VMs are single-core, to ensure a user of the free tier can reproduce it without paying extra. I will show how to add more bigger VMs later.
|
||||
|
||||

|
||||
|
||||
Once the creation of Azure VMs has finished, you should see the following:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_1c1496016083b4_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00', 'etcd-01', 'etcd-02', 'kube-00', 'kube-01', 'kube-02' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_1c1496016083b4_deployment.yml`
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Let's login to the master node like so:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
ssh -F ./output/kube_1c1496016083b4_ssh_conf kube-00
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: config file name will be different, make sure to use the one you see.
|
||||
|
||||
Check there are 2 nodes in the cluster:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Deploying the workload
|
||||
|
||||
Let's follow the Guestbook example now:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
kubectl create -f ~/guestbook-example
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You need to wait for the pods to get deployed, run the following and wait for `STATUS` to change from `Pending` to `Running`.
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
kubectl get pods --watch
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: the most time it will spend downloading Docker container images on each of the nodes.
|
||||
|
||||
Eventually you should see:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 4m
|
||||
frontend-4wahe 1/1 Running 0 4m
|
||||
frontend-6l36j 1/1 Running 0 4m
|
||||
redis-master-talmr 1/1 Running 0 4m
|
||||
redis-slave-12zfd 1/1 Running 0 4m
|
||||
redis-slave-3nbce 1/1 Running 0 4m
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Scaling
|
||||
|
||||
Two single-core nodes are certainly not enough for a production system of today. Let's scale the cluster by adding a couple of bigger nodes.
|
||||
|
||||
You will need to open another terminal window on your machine and go to the same working directory (e.g. `~/Workspace/kubernetes/docs/getting-started-guides/coreos/azure/`).
|
||||
|
||||
First, lets set the size of new VMs:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
export AZ_VM_SIZE=Large
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Now, run scale script with state file of the previous deployment and number of nodes to add:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ ./scale-kubernetes-cluster.js ./output/kube_1c1496016083b4_deployment.yml 2
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_8f984af944f572_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00',
|
||||
'etcd-01',
|
||||
'etcd-02',
|
||||
'kube-00',
|
||||
'kube-01',
|
||||
'kube-02',
|
||||
'kube-03',
|
||||
'kube-04' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_8f984af944f572_deployment.yml`
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: this step has created new files in `./output`.
|
||||
|
||||
Back on `kube-00`:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
kube-03 kubernetes.io/hostname=kube-03 Ready
|
||||
kube-04 kubernetes.io/hostname=kube-04 Ready
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You can see that two more nodes joined happily. Let's scale the number of Guestbook instances now.
|
||||
|
||||
First, double-check how many replication controllers there are:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
ONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 3
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 2
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
As there are 4 nodes, let's scale proportionally:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc redis-slave
|
||||
>>>>>>> coreos/azure: Updates for 1.0
|
||||
scaled
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc frontend
|
||||
scaled
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Check what you have now:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 4
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 4
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You now will have more instances of front-end Guestbook apps and Redis slaves; and, if you look up all pods labeled `name=frontend`, you should see one running on each node.
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~/guestbook-example $ kubectl get pods -l name=frontend
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 22m
|
||||
frontend-4wahe 1/1 Running 0 22m
|
||||
frontend-6l36j 1/1 Running 0 22m
|
||||
frontend-z9oxo 1/1 Running 0 41s
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Exposing the app to the outside world
|
||||
|
||||
There is no native Azure load-balancer support in Kubernetes 1.0, however here is how you can expose the Guestbook app to the Internet.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
./expose_guestbook_app_port.sh ./output/kube_1c1496016083b4_ssh_conf
|
||||
Guestbook app is on port 31605, will map it to port 80 on kube-00
|
||||
info: Executing command vm endpoint create
|
||||
+ Getting virtual machines
|
||||
+ Reading network configuration
|
||||
+ Updating network configuration
|
||||
info: vm endpoint create command OK
|
||||
info: Executing command vm endpoint show
|
||||
+ Getting virtual machines
|
||||
data: Name : tcp-80-31605
|
||||
data: Local port : 31605
|
||||
data: Protcol : tcp
|
||||
data: Virtual IP Address : 137.117.156.164
|
||||
data: Direct server return : Disabled
|
||||
info: vm endpoint show command OK
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
You then should be able to access it from anywhere via the Azure virtual IP for `kube-00` displayed above, i.e. `http://137.117.156.164/` in my case.
|
||||
|
||||
## Next steps
|
||||
|
||||
You now have a full-blow cluster running in Azure, congrats!
|
||||
|
||||
You should probably try deploy other [example apps](../../../../examples/) or write your own ;)
|
||||
|
||||
## Tear down...
|
||||
|
||||
If you don't wish care about the Azure bill, you can tear down the cluster. It's easy to redeploy it, as you can see.
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
./destroy-cluster.js ./output/kube_8f984af944f572_deployment.yml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: make sure to use the _latest state file_, as after scaling there is a new one.
|
||||
|
||||
By the way, with the scripts shown, you can deploy multiple clusters, if you like :)
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||||
<!-- TAG IS_VERSIONED -->
|
||||
<!-- END MUNGE: IS_VERSIONED -->
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: kube-dns-v8
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
version: v8
|
||||
kubernetes.io/cluster-service: "true"
|
||||
spec:
|
||||
containers:
|
||||
- name: etcd
|
||||
image: gcr.io/google_containers/etcd:2.0.9
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
command:
|
||||
- /usr/local/bin/etcd
|
||||
- -data-dir
|
||||
- /var/etcd/data
|
||||
- -listen-client-urls
|
||||
- http://127.0.0.1:2379,http://127.0.0.1:4001
|
||||
- -advertise-client-urls
|
||||
- http://127.0.0.1:2379,http://127.0.0.1:4001
|
||||
- -initial-cluster-token
|
||||
- skydns-etcd
|
||||
volumeMounts:
|
||||
- name: etcd-storage
|
||||
mountPath: /var/etcd/data
|
||||
- name: kube2sky
|
||||
image: gcr.io/google_containers/kube2sky:1.11
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
args:
|
||||
# command = "/kube2sky"
|
||||
- -domain=kube.local
|
||||
- -kube_master_url=http://kube-00:8080
|
||||
- name: skydns
|
||||
image: gcr.io/google_containers/skydns:2015-03-11-001
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 50Mi
|
||||
args:
|
||||
# command = "/skydns"
|
||||
- -machines=http://localhost:4001
|
||||
- -addr=0.0.0.0:53
|
||||
- -domain=kube.local
|
||||
ports:
|
||||
- containerPort: 53
|
||||
name: dns
|
||||
protocol: UDP
|
||||
- containerPort: 53
|
||||
name: dns-tcp
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 5
|
||||
- name: healthz
|
||||
image: gcr.io/google_containers/exechealthz:1.0
|
||||
resources:
|
||||
limits:
|
||||
cpu: 10m
|
||||
memory: 20Mi
|
||||
args:
|
||||
- -cmd=nslookup kubernetes.default.svc.kube.local localhost >/dev/null
|
||||
- -port=8080
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
volumes:
|
||||
- name: etcd-storage
|
||||
emptyDir: {}
|
||||
dnsPolicy: Default # Don't use cluster DNS.
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kube-dns
|
||||
namespace: kube-system
|
||||
labels:
|
||||
k8s-app: kube-dns
|
||||
kubernetes.io/cluster-service: "true"
|
||||
kubernetes.io/name: "KubeDNS"
|
||||
spec:
|
||||
selector:
|
||||
k8s-app: kube-dns
|
||||
clusterIP: 10.1.0.3
|
||||
ports:
|
||||
- name: dns
|
||||
port: 53
|
||||
protocol: UDP
|
||||
- name: dns-tcp
|
||||
port: 53
|
||||
protocol: TCP
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('child_process').fork('node_modules/azure-cli/bin/azure', ['login'].concat(process.argv));
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
## This file is used as input to deployment script, which amends it as needed.
|
||||
## More specifically, we need to add peer hosts for each but the elected peer.
|
||||
|
||||
coreos:
|
||||
units:
|
||||
- name: etcd2.service
|
||||
enable: true
|
||||
command: start
|
||||
etcd2:
|
||||
name: '%H'
|
||||
initial-cluster-token: 'etcd-cluster'
|
||||
initial-advertise-peer-urls: 'http://%H:2380'
|
||||
listen-peer-urls: 'http://%H:2380'
|
||||
listen-client-urls: 'http://0.0.0.0:2379,http://0.0.0.0:4001'
|
||||
advertise-client-urls: 'http://%H:2379,http://%H:4001'
|
||||
initial-cluster-state: 'new'
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
## This file is used as input to deployment script, which amends it as needed.
|
||||
## More specifically, we need to add environment files for as many nodes as we
|
||||
## are going to deploy.
|
||||
|
||||
write_files:
|
||||
- path: /opt/bin/curl-retry.sh
|
||||
permissions: '0755'
|
||||
owner: root
|
||||
content: |
|
||||
#!/bin/sh -x
|
||||
until curl $@
|
||||
do sleep 1
|
||||
done
|
||||
|
||||
coreos:
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
||||
units:
|
||||
- name: systemd-networkd-wait-online.service
|
||||
drop-ins:
|
||||
- name: 50-check-github-is-reachable.conf
|
||||
content: |
|
||||
[Service]
|
||||
ExecStart=/bin/sh -x -c \
|
||||
'until curl --silent --fail https://status.github.com/api/status.json | grep -q \"good\"; do sleep 2; done'
|
||||
|
||||
- name: docker.service
|
||||
drop-ins:
|
||||
- name: 50-weave-kubernetes.conf
|
||||
content: |
|
||||
[Service]
|
||||
Environment=DOCKER_OPTS='--bridge="weave" -r="false"'
|
||||
|
||||
- name: weave-network.target
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Weave Network Setup Complete
|
||||
Documentation=man:systemd.special(7)
|
||||
RefuseManualStart=no
|
||||
After=network-online.target
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kubernetes-master.target
|
||||
enable: true
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Cluster Master
|
||||
Documentation=http://kubernetes.io/
|
||||
RefuseManualStart=no
|
||||
After=weave-network.target
|
||||
Requires=weave-network.target
|
||||
ConditionHost=kube-00
|
||||
Wants=kube-apiserver.service
|
||||
Wants=kube-scheduler.service
|
||||
Wants=kube-controller-manager.service
|
||||
Wants=kube-proxy.service
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
- name: kubernetes-node.target
|
||||
enable: true
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Cluster Node
|
||||
Documentation=http://kubernetes.io/
|
||||
RefuseManualStart=no
|
||||
After=weave-network.target
|
||||
Requires=weave-network.target
|
||||
ConditionHost=!kube-00
|
||||
Wants=kube-proxy.service
|
||||
Wants=kubelet.service
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
- name: 10-weave.network
|
||||
runtime: false
|
||||
content: |
|
||||
[Match]
|
||||
Type=bridge
|
||||
Name=weave*
|
||||
[Network]
|
||||
|
||||
- name: install-weave.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Before=weave.service
|
||||
Before=weave-helper.service
|
||||
Before=docker.service
|
||||
Description=Install Weave
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=network-online.target
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStartPre=/bin/mkdir -p /opt/bin/
|
||||
ExecStartPre=/opt/bin/curl-retry.sh \
|
||||
--silent \
|
||||
--location \
|
||||
https://github.com/weaveworks/weave/releases/download/latest_release/weave \
|
||||
--output /opt/bin/weave
|
||||
ExecStartPre=/opt/bin/curl-retry.sh \
|
||||
--silent \
|
||||
--location \
|
||||
https://raw.github.com/errordeveloper/weave-demos/master/poseidon/weave-helper \
|
||||
--output /opt/bin/weave-helper
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/weave
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/weave-helper
|
||||
ExecStart=/bin/echo Weave Installed
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
WantedBy=weave.service
|
||||
|
||||
- name: weave-helper.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-weave.service
|
||||
After=docker.service
|
||||
Description=Weave Network Router
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=docker.service
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
ExecStart=/opt/bin/weave-helper
|
||||
Restart=always
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: weave.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-weave.service
|
||||
After=docker.service
|
||||
Description=Weave Network Router
|
||||
Documentation=http://docs.weave.works/
|
||||
Requires=docker.service
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
TimeoutStartSec=0
|
||||
EnvironmentFile=/etc/weave.%H.env
|
||||
ExecStartPre=/opt/bin/weave setup
|
||||
ExecStartPre=/opt/bin/weave launch $WEAVE_PEERS
|
||||
ExecStart=/usr/bin/docker attach weave
|
||||
Restart=on-failure
|
||||
Restart=always
|
||||
ExecStop=/opt/bin/weave stop
|
||||
[Install]
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: weave-create-bridge.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network.target
|
||||
After=install-weave.service
|
||||
Before=weave.service
|
||||
Before=docker.service
|
||||
Requires=network.target
|
||||
Requires=install-weave.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
EnvironmentFile=/etc/weave.%H.env
|
||||
ExecStart=/opt/bin/weave --local create-bridge
|
||||
ExecStart=/usr/bin/ip addr add dev weave $BRIDGE_ADDRESS_CIDR
|
||||
ExecStart=/usr/bin/ip route add $BREAKOUT_ROUTE dev weave scope link
|
||||
ExecStart=/usr/bin/ip route add 224.0.0.0/4 dev weave
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
WantedBy=weave-network.target
|
||||
|
||||
- name: install-kubernetes.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Before=kube-apiserver.service
|
||||
Before=kube-controller-manager.service
|
||||
Before=kubelet.service
|
||||
Before=kube-proxy.service
|
||||
Description=Download Kubernetes Binaries
|
||||
Documentation=http://kubernetes.io/
|
||||
Requires=network-online.target
|
||||
[Service]
|
||||
Environment=KUBE_RELEASE_TARBALL=https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v1.0.1/kubernetes.tar.gz
|
||||
ExecStartPre=/bin/mkdir -p /opt/
|
||||
ExecStart=/opt/bin/curl-retry.sh --silent --location $KUBE_RELEASE_TARBALL --output /tmp/kubernetes.tgz
|
||||
ExecStart=/bin/tar xzvf /tmp/kubernetes.tgz -C /tmp/
|
||||
ExecStart=/bin/tar xzvf /tmp/kubernetes/server/kubernetes-server-linux-amd64.tar.gz -C /opt
|
||||
ExecStartPost=/bin/chmod o+rx -R /opt/kubernetes
|
||||
ExecStartPost=/bin/ln -s /opt/kubernetes/server/bin/kubectl /opt/bin/
|
||||
ExecStartPost=/bin/mv /tmp/kubernetes/examples/guestbook /home/core/guestbook-example
|
||||
ExecStartPost=/bin/chown core. -R /home/core/guestbook-example
|
||||
ExecStartPost=/bin/rm -rf /tmp/kubernetes
|
||||
ExecStartPost=/bin/sed 's/# type: LoadBalancer/type: NodePort/' -i /home/core/guestbook-example/frontend-service.yaml
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-apiserver.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
Before=kube-controller-manager.service
|
||||
Before=kube-scheduler.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-apiserver
|
||||
Description=Kubernetes API Server
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-apiserver \
|
||||
--address=0.0.0.0 \
|
||||
--port=8080 \
|
||||
$ETCD_SERVERS \
|
||||
--service-cluster-ip-range=10.1.0.0/16 \
|
||||
--logtostderr=true --v=3
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kube-scheduler.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=kube-apiserver.service
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-scheduler
|
||||
Description=Kubernetes Scheduler
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=kube-apiserver.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-scheduler \
|
||||
--logtostderr=true \
|
||||
--master=127.0.0.1:8080
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kube-controller-manager.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
After=kube-apiserver.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-controller-manager
|
||||
Description=Kubernetes Controller Manager
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=kube-apiserver.service
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=kube-00
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-controller-manager \
|
||||
--master=127.0.0.1:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
|
||||
- name: kubelet.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kubelet
|
||||
Description=Kubernetes Kubelet
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
ConditionHost=!kube-00
|
||||
[Service]
|
||||
ExecStartPre=/bin/mkdir -p /etc/kubernetes/manifests/
|
||||
ExecStart=/opt/kubernetes/server/bin/kubelet \
|
||||
--address=0.0.0.0 \
|
||||
--port=10250 \
|
||||
--hostname-override=%H \
|
||||
--api-servers=http://kube-00:8080 \
|
||||
--logtostderr=true \
|
||||
--cluster-dns=10.1.0.3 \
|
||||
--cluster-domain=kube.local \
|
||||
--config=/etc/kubernetes/manifests/
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-proxy.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kube-proxy
|
||||
Description=Kubernetes Proxy
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
[Service]
|
||||
ExecStart=/opt/kubernetes/server/bin/kube-proxy \
|
||||
--master=http://kube-00:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
WantedBy=kubernetes-node.target
|
||||
|
||||
- name: kube-create-addons.service
|
||||
enable: true
|
||||
content: |
|
||||
[Unit]
|
||||
After=install-kubernetes.service
|
||||
ConditionFileIsExecutable=/opt/kubernetes/server/bin/kubectl
|
||||
ConditionPathIsDirectory=/etc/kubernetes/addons/
|
||||
ConditionHost=kube-00
|
||||
Description=Kubernetes Addons
|
||||
Documentation=http://kubernetes.io/
|
||||
Wants=install-kubernetes.service
|
||||
Wants=kube-apiserver.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=no
|
||||
ExecStart=/opt/kubernetes/server/bin/kubectl create -f /etc/kubernetes/addons/
|
||||
SuccessExitStatus=1
|
||||
[Install]
|
||||
WantedBy=kubernetes-master.target
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var azure = require('./lib/azure_wrapper.js');
|
||||
var kube = require('./lib/deployment_logic/kubernetes.js');
|
||||
|
||||
azure.create_config('kube', { 'etcd': 3, 'kube': 3 });
|
||||
|
||||
azure.run_task_queue([
|
||||
azure.queue_default_network(),
|
||||
azure.queue_storage_if_needed(),
|
||||
azure.queue_machines('etcd', 'stable',
|
||||
kube.create_etcd_cloud_config),
|
||||
azure.queue_machines('kube', 'stable',
|
||||
kube.create_node_cloud_config),
|
||||
]);
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var azure = require('./lib/azure_wrapper.js');
|
||||
|
||||
azure.destroy_cluster(process.argv[2]);
|
||||
|
||||
console.log('The cluster had been destroyed, you can delete the state file now.');
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2014 The Kubernetes Authors 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.
|
||||
|
||||
set -e
|
||||
|
||||
[ ! -z $1 ] || (echo Usage: $0 ssh_conf; exit 1)
|
||||
|
||||
fe_port=$(ssh -F $1 kube-00 \
|
||||
"/opt/bin/kubectl get -o template --template='{{(index .spec.ports 0).nodePort}}' services frontend -L name=frontend" \
|
||||
)
|
||||
|
||||
echo "Guestbook app is on port $fe_port, will map it to port 80 on kube-00"
|
||||
|
||||
./node_modules/.bin/azure vm endpoint create kube-00 80 $fe_port
|
||||
|
||||
./node_modules/.bin/azure vm endpoint show kube-00 tcp-80-${fe_port}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 286 KiB |
@@ -0,0 +1,289 @@
|
||||
---
|
||||
layout: docwithnav
|
||||
title: "Kubernetes on Azure with CoreOS and Weave"
|
||||
---
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
Kubernetes on Azure with CoreOS and [Weave](http://weave.works)
|
||||
---------------------------------------------------------------
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Let's go!](#lets-go)
|
||||
- [Deploying the workload](#deploying-the-workload)
|
||||
- [Scaling](#scaling)
|
||||
- [Exposing the app to the outside world](#exposing-the-app-to-the-outside-world)
|
||||
- [Next steps](#next-steps)
|
||||
- [Tear down...](#tear-down)
|
||||
|
||||
## Introduction
|
||||
|
||||
In this guide I will demonstrate how to deploy a Kubernetes cluster to Azure cloud. You will be using CoreOS with Weave, which implements simple and secure networking, in a transparent, yet robust way. The purpose of this guide is to provide an out-of-the-box implementation that can ultimately be taken into production with little change. It will demonstrate how to provision a dedicated Kubernetes master and etcd nodes, and show how to scale the cluster with ease.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. You need an Azure account.
|
||||
|
||||
## Let's go!
|
||||
|
||||
To get started, you need to checkout the code:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
git clone https://github.com/kubernetes/kubernetes
|
||||
cd kubernetes/docs/getting-started-guides/coreos/azure/
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You will need to have [Node.js installed](http://nodejs.org/download/) on you machine. If you have previously used Azure CLI, you should have it already.
|
||||
|
||||
First, you need to install some of the dependencies with
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
npm install
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Now, all you need to do is:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
./azure-login.js -u <your_username>
|
||||
./create-kubernetes-cluster.js
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
This script will provision a cluster suitable for production use, where there is a ring of 3 dedicated etcd nodes: 1 kubernetes master and 2 kubernetes nodes. The `kube-00` VM will be the master, your work loads are only to be deployed on the nodes, `kube-01` and `kube-02`. Initially, all VMs are single-core, to ensure a user of the free tier can reproduce it without paying extra. I will show how to add more bigger VMs later.
|
||||
|
||||

|
||||
|
||||
Once the creation of Azure VMs has finished, you should see the following:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_1c1496016083b4_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00', 'etcd-01', 'etcd-02', 'kube-00', 'kube-01', 'kube-02' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_1c1496016083b4_deployment.yml`
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Let's login to the master node like so:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
ssh -F ./output/kube_1c1496016083b4_ssh_conf kube-00
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: config file name will be different, make sure to use the one you see.
|
||||
|
||||
Check there are 2 nodes in the cluster:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Deploying the workload
|
||||
|
||||
Let's follow the Guestbook example now:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
kubectl create -f ~/guestbook-example
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You need to wait for the pods to get deployed, run the following and wait for `STATUS` to change from `Pending` to `Running`.
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
kubectl get pods --watch
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: the most time it will spend downloading Docker container images on each of the nodes.
|
||||
|
||||
Eventually you should see:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 4m
|
||||
frontend-4wahe 1/1 Running 0 4m
|
||||
frontend-6l36j 1/1 Running 0 4m
|
||||
redis-master-talmr 1/1 Running 0 4m
|
||||
redis-slave-12zfd 1/1 Running 0 4m
|
||||
redis-slave-3nbce 1/1 Running 0 4m
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Scaling
|
||||
|
||||
Two single-core nodes are certainly not enough for a production system of today. Let's scale the cluster by adding a couple of bigger nodes.
|
||||
|
||||
You will need to open another terminal window on your machine and go to the same working directory (e.g. `~/Workspace/kubernetes/docs/getting-started-guides/coreos/azure/`).
|
||||
|
||||
First, lets set the size of new VMs:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
export AZ_VM_SIZE=Large
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Now, run scale script with state file of the previous deployment and number of nodes to add:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ ./scale-kubernetes-cluster.js ./output/kube_1c1496016083b4_deployment.yml 2
|
||||
...
|
||||
azure_wrapper/info: Saved SSH config, you can use it like so: `ssh -F ./output/kube_8f984af944f572_ssh_conf <hostname>`
|
||||
azure_wrapper/info: The hosts in this deployment are:
|
||||
[ 'etcd-00',
|
||||
'etcd-01',
|
||||
'etcd-02',
|
||||
'kube-00',
|
||||
'kube-01',
|
||||
'kube-02',
|
||||
'kube-03',
|
||||
'kube-04' ]
|
||||
azure_wrapper/info: Saved state into `./output/kube_8f984af944f572_deployment.yml`
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: this step has created new files in `./output`.
|
||||
|
||||
Back on `kube-00`:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get nodes
|
||||
NAME LABELS STATUS
|
||||
kube-01 kubernetes.io/hostname=kube-01 Ready
|
||||
kube-02 kubernetes.io/hostname=kube-02 Ready
|
||||
kube-03 kubernetes.io/hostname=kube-03 Ready
|
||||
kube-04 kubernetes.io/hostname=kube-04 Ready
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You can see that two more nodes joined happily. Let's scale the number of Guestbook instances now.
|
||||
|
||||
First, double-check how many replication controllers there are:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
ONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 3
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 2
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
As there are 4 nodes, let's scale proportionally:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc redis-slave
|
||||
>>>>>>> coreos/azure: Updates for 1.0
|
||||
scaled
|
||||
core@kube-00 ~ $ kubectl scale --replicas=4 rc frontend
|
||||
scaled
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Check what you have now:
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~ $ kubectl get rc
|
||||
CONTROLLER CONTAINER(S) IMAGE(S) SELECTOR REPLICAS
|
||||
frontend php-redis kubernetes/example-guestbook-php-redis:v2 name=frontend 4
|
||||
redis-master master redis name=redis-master 1
|
||||
redis-slave worker kubernetes/redis-slave:v2 name=redis-slave 4
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
You now will have more instances of front-end Guestbook apps and Redis slaves; and, if you look up all pods labeled `name=frontend`, you should see one running on each node.
|
||||
|
||||
{% highlight console %}
|
||||
{% raw %}
|
||||
core@kube-00 ~/guestbook-example $ kubectl get pods -l name=frontend
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
frontend-0a9xi 1/1 Running 0 22m
|
||||
frontend-4wahe 1/1 Running 0 22m
|
||||
frontend-6l36j 1/1 Running 0 22m
|
||||
frontend-z9oxo 1/1 Running 0 41s
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
## Exposing the app to the outside world
|
||||
|
||||
There is no native Azure load-balancer support in Kubernetes 1.0, however here is how you can expose the Guestbook app to the Internet.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
./expose_guestbook_app_port.sh ./output/kube_1c1496016083b4_ssh_conf
|
||||
Guestbook app is on port 31605, will map it to port 80 on kube-00
|
||||
info: Executing command vm endpoint create
|
||||
+ Getting virtual machines
|
||||
+ Reading network configuration
|
||||
+ Updating network configuration
|
||||
info: vm endpoint create command OK
|
||||
info: Executing command vm endpoint show
|
||||
+ Getting virtual machines
|
||||
data: Name : tcp-80-31605
|
||||
data: Local port : 31605
|
||||
data: Protcol : tcp
|
||||
data: Virtual IP Address : 137.117.156.164
|
||||
data: Direct server return : Disabled
|
||||
info: vm endpoint show command OK
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
You then should be able to access it from anywhere via the Azure virtual IP for `kube-00` displayed above, i.e. `http://137.117.156.164/` in my case.
|
||||
|
||||
## Next steps
|
||||
|
||||
You now have a full-blow cluster running in Azure, congrats!
|
||||
|
||||
You should probably try deploy other [example apps](../../../../examples/) or write your own ;)
|
||||
|
||||
## Tear down...
|
||||
|
||||
If you don't wish care about the Azure bill, you can tear down the cluster. It's easy to redeploy it, as you can see.
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
./destroy-cluster.js ./output/kube_8f984af944f572_deployment.yml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
> Note: make sure to use the _latest state file_, as after scaling there is a new one.
|
||||
|
||||
By the way, with the scripts shown, you can deploy multiple clusters, if you like :)
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||||
<!-- TAG IS_VERSIONED -->
|
||||
<!-- END MUNGE: IS_VERSIONED -->
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@@ -0,0 +1,271 @@
|
||||
var _ = require('underscore');
|
||||
|
||||
var fs = require('fs');
|
||||
var cp = require('child_process');
|
||||
|
||||
var yaml = require('js-yaml');
|
||||
|
||||
var openssl = require('openssl-wrapper');
|
||||
|
||||
var clr = require('colors');
|
||||
var inspect = require('util').inspect;
|
||||
|
||||
var util = require('./util.js');
|
||||
|
||||
var coreos_image_ids = {
|
||||
'stable': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-717.3.0',
|
||||
'beta': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Beta-723.3.0', // untested
|
||||
'alpha': '2b171e93f07c4903bcad35bda10acf22__CoreOS-Alpha-745.1.0' // untested
|
||||
};
|
||||
|
||||
var conf = {};
|
||||
|
||||
var hosts = {
|
||||
collection: [],
|
||||
ssh_port_counter: 2200,
|
||||
};
|
||||
|
||||
var task_queue = [];
|
||||
|
||||
exports.run_task_queue = function (dummy) {
|
||||
var tasks = {
|
||||
todo: task_queue,
|
||||
done: [],
|
||||
};
|
||||
|
||||
var pop_task = function() {
|
||||
console.log(clr.yellow('azure_wrapper/task:'), clr.grey(inspect(tasks)));
|
||||
var ret = {};
|
||||
ret.current = tasks.todo.shift();
|
||||
ret.remaining = tasks.todo.length;
|
||||
return ret;
|
||||
};
|
||||
|
||||
(function iter (task) {
|
||||
if (task.current === undefined) {
|
||||
if (conf.destroying === undefined) {
|
||||
create_ssh_conf();
|
||||
save_state();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (task.current.length !== 0) {
|
||||
console.log(clr.yellow('azure_wrapper/exec:'), clr.blue(inspect(task.current)));
|
||||
cp.fork('node_modules/azure-cli/bin/azure', task.current)
|
||||
.on('exit', function (code, signal) {
|
||||
tasks.done.push({
|
||||
code: code,
|
||||
signal: signal,
|
||||
what: task.current.join(' '),
|
||||
remaining: task.remaining,
|
||||
});
|
||||
if (code !== 0 && conf.destroying === undefined) {
|
||||
console.log(clr.red('azure_wrapper/fail: Exiting due to an error.'));
|
||||
save_state();
|
||||
console.log(clr.cyan('azure_wrapper/info: You probably want to destroy and re-run.'));
|
||||
process.abort();
|
||||
} else {
|
||||
iter(pop_task());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
iter(pop_task());
|
||||
}
|
||||
}
|
||||
})(pop_task());
|
||||
};
|
||||
|
||||
var save_state = function () {
|
||||
var file_name = util.join_output_file_path(conf.name, 'deployment.yml');
|
||||
try {
|
||||
conf.hosts = hosts.collection;
|
||||
fs.writeFileSync(file_name, yaml.safeDump(conf));
|
||||
console.log(clr.yellow('azure_wrapper/info: Saved state into `%s`'), file_name);
|
||||
} catch (e) {
|
||||
console.log(clr.red(e));
|
||||
}
|
||||
};
|
||||
|
||||
var load_state = function (file_name) {
|
||||
try {
|
||||
conf = yaml.safeLoad(fs.readFileSync(file_name, 'utf8'));
|
||||
console.log(clr.yellow('azure_wrapper/info: Loaded state from `%s`'), file_name);
|
||||
return conf;
|
||||
} catch (e) {
|
||||
console.log(clr.red(e));
|
||||
}
|
||||
};
|
||||
|
||||
var create_ssh_key = function (prefix) {
|
||||
var opts = {
|
||||
x509: true,
|
||||
nodes: true,
|
||||
newkey: 'rsa:2048',
|
||||
subj: '/O=Weaveworks, Inc./L=London/C=GB/CN=weave.works',
|
||||
keyout: util.join_output_file_path(prefix, 'ssh.key'),
|
||||
out: util.join_output_file_path(prefix, 'ssh.pem'),
|
||||
};
|
||||
openssl.exec('req', opts, function (err, buffer) {
|
||||
if (err) console.log(clr.red(err));
|
||||
fs.chmod(opts.keyout, '0600', function (err) {
|
||||
if (err) console.log(clr.red(err));
|
||||
});
|
||||
});
|
||||
return {
|
||||
key: opts.keyout,
|
||||
pem: opts.out,
|
||||
}
|
||||
}
|
||||
|
||||
var create_ssh_conf = function () {
|
||||
var file_name = util.join_output_file_path(conf.name, 'ssh_conf');
|
||||
var ssh_conf_head = [
|
||||
"Host *",
|
||||
"\tHostname " + conf.resources['service'] + ".cloudapp.net",
|
||||
"\tUser core",
|
||||
"\tCompression yes",
|
||||
"\tLogLevel FATAL",
|
||||
"\tStrictHostKeyChecking no",
|
||||
"\tUserKnownHostsFile /dev/null",
|
||||
"\tIdentitiesOnly yes",
|
||||
"\tIdentityFile " + conf.resources['ssh_key']['key'],
|
||||
"\n",
|
||||
];
|
||||
|
||||
fs.writeFileSync(file_name, ssh_conf_head.concat(_.map(hosts.collection, function (host) {
|
||||
return _.template("Host <%= name %>\n\tPort <%= port %>\n")(host);
|
||||
})).join('\n'));
|
||||
console.log(clr.yellow('azure_wrapper/info:'), clr.green('Saved SSH config, you can use it like so: `ssh -F ', file_name, '<hostname>`'));
|
||||
console.log(clr.yellow('azure_wrapper/info:'), clr.green('The hosts in this deployment are:\n'), _.map(hosts.collection, function (host) { return host.name; }));
|
||||
};
|
||||
|
||||
var get_location = function () {
|
||||
if (process.env['AZ_AFFINITY']) {
|
||||
return '--affinity-group=' + process.env['AZ_AFFINITY'];
|
||||
} else if (process.env['AZ_LOCATION']) {
|
||||
return '--location=' + process.env['AZ_LOCATION'];
|
||||
} else {
|
||||
return '--location=West Europe';
|
||||
}
|
||||
}
|
||||
var get_vm_size = function () {
|
||||
if (process.env['AZ_VM_SIZE']) {
|
||||
return '--vm-size=' + process.env['AZ_VM_SIZE'];
|
||||
} else {
|
||||
return '--vm-size=Small';
|
||||
}
|
||||
}
|
||||
|
||||
exports.queue_default_network = function () {
|
||||
task_queue.push([
|
||||
'network', 'vnet', 'create',
|
||||
get_location(),
|
||||
'--address-space=172.16.0.0',
|
||||
conf.resources['vnet'],
|
||||
]);
|
||||
}
|
||||
|
||||
exports.queue_storage_if_needed = function() {
|
||||
if (!process.env['AZURE_STORAGE_ACCOUNT']) {
|
||||
conf.resources['storage_account'] = util.rand_suffix;
|
||||
task_queue.push([
|
||||
'storage', 'account', 'create',
|
||||
'--type=LRS',
|
||||
get_location(),
|
||||
conf.resources['storage_account'],
|
||||
]);
|
||||
process.env['AZURE_STORAGE_ACCOUNT'] = conf.resources['storage_account'];
|
||||
} else {
|
||||
// Preserve it for resizing, so we don't create a new one by accedent,
|
||||
// when the environment variable is unset
|
||||
conf.resources['storage_account'] = process.env['AZURE_STORAGE_ACCOUNT'];
|
||||
}
|
||||
};
|
||||
|
||||
exports.queue_machines = function (name_prefix, coreos_update_channel, cloud_config_creator) {
|
||||
var x = conf.nodes[name_prefix];
|
||||
var vm_create_base_args = [
|
||||
'vm', 'create',
|
||||
get_location(),
|
||||
get_vm_size(),
|
||||
'--connect=' + conf.resources['service'],
|
||||
'--virtual-network-name=' + conf.resources['vnet'],
|
||||
'--no-ssh-password',
|
||||
'--ssh-cert=' + conf.resources['ssh_key']['pem'],
|
||||
];
|
||||
|
||||
var cloud_config = cloud_config_creator(x, conf);
|
||||
|
||||
var next_host = function (n) {
|
||||
hosts.ssh_port_counter += 1;
|
||||
var host = { name: util.hostname(n, name_prefix), port: hosts.ssh_port_counter };
|
||||
if (cloud_config instanceof Array) {
|
||||
host.cloud_config_file = cloud_config[n];
|
||||
} else {
|
||||
host.cloud_config_file = cloud_config;
|
||||
}
|
||||
hosts.collection.push(host);
|
||||
return _.map([
|
||||
"--vm-name=<%= name %>",
|
||||
"--ssh=<%= port %>",
|
||||
"--custom-data=<%= cloud_config_file %>",
|
||||
], function (arg) { return _.template(arg)(host); });
|
||||
};
|
||||
|
||||
task_queue = task_queue.concat(_(x).times(function (n) {
|
||||
if (conf.resizing && n < conf.old_size) {
|
||||
return [];
|
||||
} else {
|
||||
return vm_create_base_args.concat(next_host(n), [
|
||||
coreos_image_ids[coreos_update_channel], 'core',
|
||||
]);
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
exports.create_config = function (name, nodes) {
|
||||
conf = {
|
||||
name: name,
|
||||
nodes: nodes,
|
||||
weave_salt: util.rand_string(),
|
||||
resources: {
|
||||
vnet: [name, 'internal-vnet', util.rand_suffix].join('-'),
|
||||
service: [name, util.rand_suffix].join('-'),
|
||||
ssh_key: create_ssh_key(name),
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
exports.destroy_cluster = function (state_file) {
|
||||
load_state(state_file);
|
||||
if (conf.hosts === undefined) {
|
||||
console.log(clr.red('azure_wrapper/fail: Nothing to delete.'));
|
||||
process.abort();
|
||||
}
|
||||
|
||||
conf.destroying = true;
|
||||
task_queue = _.map(conf.hosts, function (host) {
|
||||
return ['vm', 'delete', '--quiet', '--blob-delete', host.name];
|
||||
});
|
||||
|
||||
task_queue.push(['network', 'vnet', 'delete', '--quiet', conf.resources['vnet']]);
|
||||
task_queue.push(['storage', 'account', 'delete', '--quiet', conf.resources['storage_account']]);
|
||||
|
||||
exports.run_task_queue();
|
||||
};
|
||||
|
||||
exports.load_state_for_resizing = function (state_file, node_type, new_nodes) {
|
||||
load_state(state_file);
|
||||
if (conf.hosts === undefined) {
|
||||
console.log(clr.red('azure_wrapper/fail: Nothing to look at.'));
|
||||
process.abort();
|
||||
}
|
||||
conf.resizing = true;
|
||||
conf.old_size = conf.nodes[node_type];
|
||||
conf.old_state_file = state_file;
|
||||
conf.nodes[node_type] += new_nodes;
|
||||
hosts.collection = conf.hosts;
|
||||
hosts.ssh_port_counter += conf.hosts.length;
|
||||
process.env['AZURE_STORAGE_ACCOUNT'] = conf.resources['storage_account'];
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
var _ = require('underscore');
|
||||
var fs = require('fs');
|
||||
var yaml = require('js-yaml');
|
||||
var colors = require('colors/safe');
|
||||
|
||||
var write_cloud_config_from_object = function (data, output_file) {
|
||||
try {
|
||||
fs.writeFileSync(output_file, [
|
||||
'#cloud-config',
|
||||
yaml.safeDump(data),
|
||||
].join("\n"));
|
||||
return output_file;
|
||||
} catch (e) {
|
||||
console.log(colors.red(e));
|
||||
}
|
||||
};
|
||||
|
||||
exports.generate_environment_file_entry_from_object = function (hostname, environ) {
|
||||
var data = {
|
||||
hostname: hostname,
|
||||
environ_array: _.map(environ, function (value, key) {
|
||||
return [key.toUpperCase(), JSON.stringify(value.toString())].join('=');
|
||||
}),
|
||||
};
|
||||
|
||||
return {
|
||||
permissions: '0600',
|
||||
owner: 'root',
|
||||
content: _.template("<%= environ_array.join('\\n') %>\n")(data),
|
||||
path: _.template("/etc/weave.<%= hostname %>.env")(data),
|
||||
};
|
||||
};
|
||||
|
||||
exports.process_template = function (input_file, output_file, processor) {
|
||||
var data = {};
|
||||
try {
|
||||
data = yaml.safeLoad(fs.readFileSync(input_file, 'utf8'));
|
||||
} catch (e) {
|
||||
console.log(colors.red(e));
|
||||
}
|
||||
return write_cloud_config_from_object(processor(_.clone(data)), output_file);
|
||||
};
|
||||
|
||||
exports.write_files_from = function (local_dir, remote_dir) {
|
||||
try {
|
||||
return _.map(fs.readdirSync(local_dir), function (fn) {
|
||||
return {
|
||||
path: [remote_dir, fn].join('/'),
|
||||
owner: 'root',
|
||||
permissions: '0640',
|
||||
encoding: 'base64',
|
||||
content: fs.readFileSync([local_dir, fn].join('/')).toString('base64'),
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(colors.red(e));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
var _ = require('underscore');
|
||||
_.mixin(require('underscore.string').exports());
|
||||
|
||||
var util = require('../util.js');
|
||||
var cloud_config = require('../cloud_config.js');
|
||||
|
||||
|
||||
etcd_initial_cluster_conf_self = function (conf) {
|
||||
var port = '2380';
|
||||
|
||||
var data = {
|
||||
nodes: _(conf.nodes.etcd).times(function (n) {
|
||||
var host = util.hostname(n, 'etcd');
|
||||
return [host, [host, port].join(':')].join('=http://');
|
||||
}),
|
||||
};
|
||||
|
||||
return {
|
||||
'name': 'etcd2.service',
|
||||
'drop-ins': [{
|
||||
'name': '50-etcd-initial-cluster.conf',
|
||||
'content': _.template("[Service]\nEnvironment=ETCD_INITIAL_CLUSTER=<%= nodes.join(',') %>\n")(data),
|
||||
}],
|
||||
};
|
||||
};
|
||||
|
||||
etcd_initial_cluster_conf_kube = function (conf) {
|
||||
var port = '4001';
|
||||
|
||||
var data = {
|
||||
nodes: _(conf.nodes.etcd).times(function (n) {
|
||||
var host = util.hostname(n, 'etcd');
|
||||
return 'http://' + [host, port].join(':');
|
||||
}),
|
||||
};
|
||||
|
||||
return {
|
||||
'name': 'kube-apiserver.service',
|
||||
'drop-ins': [{
|
||||
'name': '50-etcd-initial-cluster.conf',
|
||||
'content': _.template("[Service]\nEnvironment=ETCD_SERVERS=--etcd-servers=<%= nodes.join(',') %>\n")(data),
|
||||
}],
|
||||
};
|
||||
};
|
||||
|
||||
exports.create_etcd_cloud_config = function (node_count, conf) {
|
||||
var input_file = './cloud_config_templates/kubernetes-cluster-etcd-node-template.yml';
|
||||
var output_file = util.join_output_file_path('kubernetes-cluster-etcd-nodes', 'generated.yml');
|
||||
|
||||
return cloud_config.process_template(input_file, output_file, function(data) {
|
||||
data.coreos.units.push(etcd_initial_cluster_conf_self(conf));
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
exports.create_node_cloud_config = function (node_count, conf) {
|
||||
var elected_node = 0;
|
||||
|
||||
var input_file = './cloud_config_templates/kubernetes-cluster-main-nodes-template.yml';
|
||||
var output_file = util.join_output_file_path('kubernetes-cluster-main-nodes', 'generated.yml');
|
||||
|
||||
var make_node_config = function (n) {
|
||||
return cloud_config.generate_environment_file_entry_from_object(util.hostname(n, 'kube'), {
|
||||
weave_password: conf.weave_salt,
|
||||
weave_peers: n === elected_node ? "" : util.hostname(elected_node, 'kube'),
|
||||
breakout_route: util.ipv4([10, 2, 0, 0], 16),
|
||||
bridge_address_cidr: util.ipv4([10, 2, n, 1], 24),
|
||||
});
|
||||
};
|
||||
|
||||
var write_files_extra = cloud_config.write_files_from('addons', '/etc/kubernetes/addons');
|
||||
return cloud_config.process_template(input_file, output_file, function(data) {
|
||||
data.write_files = data.write_files.concat(_(node_count).times(make_node_config), write_files_extra);
|
||||
data.coreos.units.push(etcd_initial_cluster_conf_kube(conf));
|
||||
return data;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
var _ = require('underscore');
|
||||
_.mixin(require('underscore.string').exports());
|
||||
|
||||
exports.ipv4 = function (ocets, prefix) {
|
||||
return {
|
||||
ocets: ocets,
|
||||
prefix: prefix,
|
||||
toString: function () {
|
||||
return [ocets.join('.'), prefix].join('/');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.hostname = function hostname (n, prefix) {
|
||||
return _.template("<%= pre %>-<%= seq %>")({
|
||||
pre: prefix || 'core',
|
||||
seq: _.pad(n, 2, '0'),
|
||||
});
|
||||
};
|
||||
|
||||
exports.rand_string = function () {
|
||||
var crypto = require('crypto');
|
||||
var shasum = crypto.createHash('sha256');
|
||||
shasum.update(crypto.randomBytes(256));
|
||||
return shasum.digest('hex');
|
||||
};
|
||||
|
||||
|
||||
exports.rand_suffix = exports.rand_string().substring(50);
|
||||
|
||||
exports.join_output_file_path = function(prefix, suffix) {
|
||||
return './output/' + [prefix, exports.rand_suffix, suffix].join('_');
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "coreos-azure-weave",
|
||||
"version": "1.0.0",
|
||||
"description": "Small utility to bring up a woven CoreOS cluster",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Ilya Dmitrichenko <errordeveloper@gmail.com>",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
"azure-cli": "^0.9.5",
|
||||
"colors": "^1.0.3",
|
||||
"js-yaml": "^3.2.5",
|
||||
"openssl-wrapper": "^0.2.1",
|
||||
"underscore": "^1.7.0",
|
||||
"underscore.string": "^3.0.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var azure = require('./lib/azure_wrapper.js');
|
||||
var kube = require('./lib/deployment_logic/kubernetes.js');
|
||||
|
||||
azure.load_state_for_resizing(process.argv[2], 'kube', parseInt(process.argv[3] || 1));
|
||||
|
||||
azure.run_task_queue([
|
||||
azure.queue_machines('kube', 'stable', kube.create_node_cloud_config),
|
||||
]);
|
||||
@@ -0,0 +1,152 @@
|
||||
---
|
||||
layout: docwithnav
|
||||
title: "Bare Metal CoreOS with Kubernetes and Project Calico"
|
||||
---
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
Bare Metal CoreOS with Kubernetes and Project Calico
|
||||
------------------------------------------
|
||||
This guide explains how to deploy a bare-metal Kubernetes cluster on CoreOS using [Calico networking](http://www.projectcalico.org).
|
||||
|
||||
Specifically, this guide will have you do the following:
|
||||
- Deploy a Kubernetes master node on CoreOS using cloud-config
|
||||
- Deploy two Kubernetes compute nodes with Calico Networking using cloud-config
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. At least three bare-metal machines (or VMs) to work with. This guide will configure them as follows
|
||||
- 1 Kubernetes Master
|
||||
- 2 Kubernetes Nodes
|
||||
2. Your nodes should have IP connectivity.
|
||||
|
||||
## Cloud-config
|
||||
|
||||
This guide will use [cloud-config](https://coreos.com/docs/cluster-management/setup/cloudinit-cloud-config/) to configure each of the nodes in our Kubernetes cluster.
|
||||
|
||||
For ease of distribution, the cloud-config files required for this demonstration can be found on [GitHub](https://github.com/projectcalico/calico-kubernetes-coreos-demo).
|
||||
|
||||
This repo includes two cloud config files:
|
||||
- `master-config.yaml`: Cloud-config for the Kubernetes master
|
||||
- `node-config.yaml`: Cloud-config for each Kubernetes compute host
|
||||
|
||||
In the next few steps you will be asked to configure these files and host them on an HTTP server where your cluster can access them.
|
||||
|
||||
## Building Kubernetes
|
||||
|
||||
To get the Kubernetes source, clone the GitHub repo, and build the binaries.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
git clone https://github.com/kubernetes/kubernetes.git
|
||||
cd kubernetes
|
||||
./build/release.sh
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
Once the binaries are built, host the entire `<kubernetes>/_output/dockerized/bin/<OS>/<ARCHITECTURE>/` folder on an accessible HTTP server so they can be accessed by the cloud-config. You'll point your cloud-config files at this HTTP server later.
|
||||
|
||||
## Download CoreOS
|
||||
|
||||
Let's download the CoreOS bootable ISO. We'll use this image to boot and install CoreOS on each server.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_iso_image.iso
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
You can also download the ISO from the [CoreOS website](https://coreos.com/docs/running-coreos/platforms/iso/).
|
||||
|
||||
## Configure the Kubernetes Master
|
||||
|
||||
Once you've downloaded the image, use it to boot your Kubernetes Master server. Once booted, you should be automatically logged in as the `core` user.
|
||||
|
||||
Let's get the master-config.yaml and fill in the necessary variables. Run the following commands on your HTTP server to get the cloud-config files.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
git clone https://github.com/Metaswitch/calico-kubernetes-demo.git
|
||||
cd calico-kubernetes-demo/coreos
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
You'll need to replace the following variables in the `master-config.yaml` file to match your deployment.
|
||||
- `<SSH_PUBLIC_KEY>`: The public key you will use for SSH access to this server.
|
||||
- `<KUBERNETES_LOC>`: The address used to get the kubernetes binaries over HTTP.
|
||||
|
||||
> **Note:** The config will prepend `"http://"` and append `"/(kubernetes | kubectl | ...)"` to your `KUBERNETES_LOC` variable:, format accordingly
|
||||
|
||||
Host the modified `master-config.yaml` file and pull it on to your Kubernetes Master server.
|
||||
|
||||
The CoreOS bootable ISO comes with a tool called `coreos-install` which will allow us to install CoreOS to disk and configure the install using cloud-config. The following command will download and install stable CoreOS, using the master-config.yaml file for configuration.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
sudo coreos-install -d /dev/sda -C stable -c master-config.yaml
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
Once complete, eject the bootable ISO and restart the server. When it comes back up, you should have SSH access as the `core` user using the public key provided in the master-config.yaml file.
|
||||
|
||||
## Configure the compute hosts
|
||||
|
||||
>The following steps will set up a Kubernetes node for use as a compute host. This demo uses two compute hosts, so you should run the following steps on each.
|
||||
|
||||
First, boot up your node using the bootable ISO we downloaded earlier. You should be automatically logged in as the `core` user.
|
||||
|
||||
Let's modify the `node-config.yaml` cloud-config file on your HTTP server. Make a copy for this node, and fill in the necessary variables.
|
||||
|
||||
You'll need to replace the following variables in the `node-config.yaml` file to match your deployment.
|
||||
- `<HOSTNAME>`: Hostname for this node (e.g. kube-node1, kube-node2)
|
||||
- `<SSH_PUBLIC_KEY>`: The public key you will use for SSH access to this server.
|
||||
- `<KUBERNETES_MASTER>`: The IPv4 address of the Kubernetes master.
|
||||
- `<KUBERNETES_LOC>`: The address to use in order to get the kubernetes binaries over HTTP.
|
||||
- `<DOCKER_BRIDGE_IP>`: The IP and subnet to use for pods on this node. By default, this should fall within the 192.168.0.0/16 subnet.
|
||||
|
||||
> Note: The DOCKER_BRIDGE_IP is the range used by this Kubernetes node to assign IP addresses to pods on this node. This subnet must not overlap with the subnets assigned to the other Kubernetes nodes in your cluster. Calico expects each DOCKER_BRIDGE_IP subnet to fall within 192.168.0.0/16 by default (e.g. 192.168.1.1/24 for node 1), but if you'd like to use pod IPs within a different subnet, simply run `calicoctl pool add <your_subnet>` and select DOCKER_BRIDGE_IP accordingly.
|
||||
|
||||
Host the modified `node-config.yaml` file and pull it on to your Kubernetes node.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
wget http://<http_server_ip>/node-config.yaml
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
Install and configure CoreOS on the node using the following command.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
sudo coreos-install -d /dev/sda -C stable -c node-config.yaml
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
Once complete, restart the server. When it comes back up, you should have SSH access as the `core` user using the public key provided in the `node-config.yaml` file. It will take some time for the node to be fully configured. Once fully configured, you can check that the node is running with the following command on the Kubernetes master.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
/home/core/kubectl get nodes
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
## Testing the Cluster
|
||||
|
||||
You should now have a functional bare-metal Kubernetes cluster with one master and two compute hosts.
|
||||
Try running the [guestbook demo](../../../examples/guestbook/) to test out your new cluster!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||||
<!-- TAG IS_VERSIONED -->
|
||||
<!-- END MUNGE: IS_VERSIONED -->
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
||||
@@ -0,0 +1,691 @@
|
||||
---
|
||||
layout: docwithnav
|
||||
title: "Bare Metal CoreOS with Kubernetes (OFFLINE)"
|
||||
---
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
Bare Metal CoreOS with Kubernetes (OFFLINE)
|
||||
------------------------------------------
|
||||
Deploy a CoreOS running Kubernetes environment. This particular guild is made to help those in an OFFLINE system, wither for testing a POC before the real deal, or you are restricted to be totally offline for your applications.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [High Level Design](#high-level-design)
|
||||
- [This Guides variables](#this-guides-variables)
|
||||
- [Setup PXELINUX CentOS](#setup-pxelinux-centos)
|
||||
- [Adding CoreOS to PXE](#adding-coreos-to-pxe)
|
||||
- [DHCP configuration](#dhcp-configuration)
|
||||
- [Kubernetes](#kubernetes)
|
||||
- [Cloud Configs](#cloud-configs)
|
||||
- [master.yml](#masteryml)
|
||||
- [node.yml](#nodeyml)
|
||||
- [New pxelinux.cfg file](#new-pxelinuxcfg-file)
|
||||
- [Specify the pxelinux targets](#specify-the-pxelinux-targets)
|
||||
- [Creating test pod](#creating-test-pod)
|
||||
- [Helping commands for debugging](#helping-commands-for-debugging)
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Installed *CentOS 6* for PXE server
|
||||
2. At least two bare metal nodes to work with
|
||||
|
||||
## High Level Design
|
||||
|
||||
1. Manage the tftp directory
|
||||
* /tftpboot/(coreos)(centos)(RHEL)
|
||||
* /tftpboot/pxelinux.0/(MAC) -> linked to Linux image config file
|
||||
2. Update per install the link for pxelinux
|
||||
3. Update the DHCP config to reflect the host needing deployment
|
||||
4. Setup nodes to deploy CoreOS creating a etcd cluster.
|
||||
5. Have no access to the public [etcd discovery tool](https://discovery.etcd.io/).
|
||||
6. Installing the CoreOS slaves to become Kubernetes nodes.
|
||||
|
||||
## This Guides variables
|
||||
|
||||
| Node Description | MAC | IP |
|
||||
| :---------------------------- | :---------------: | :---------: |
|
||||
| CoreOS/etcd/Kubernetes Master | d0:00:67:13:0d:00 | 10.20.30.40 |
|
||||
| CoreOS Slave 1 | d0:00:67:13:0d:01 | 10.20.30.41 |
|
||||
| CoreOS Slave 2 | d0:00:67:13:0d:02 | 10.20.30.42 |
|
||||
|
||||
|
||||
## Setup PXELINUX CentOS
|
||||
|
||||
To setup CentOS PXELINUX environment there is a complete [guide here](http://docs.fedoraproject.org/en-US/Fedora/7/html/Installation_Guide/ap-pxe-server.html). This section is the abbreviated version.
|
||||
|
||||
1. Install packages needed on CentOS
|
||||
|
||||
sudo yum install tftp-server dhcp syslinux
|
||||
|
||||
2. `vi /etc/xinetd.d/tftp` to enable tftp service and change disable to 'no'
|
||||
disable = no
|
||||
|
||||
3. Copy over the syslinux images we will need.
|
||||
|
||||
su -
|
||||
mkdir -p /tftpboot
|
||||
cd /tftpboot
|
||||
cp /usr/share/syslinux/pxelinux.0 /tftpboot
|
||||
cp /usr/share/syslinux/menu.c32 /tftpboot
|
||||
cp /usr/share/syslinux/memdisk /tftpboot
|
||||
cp /usr/share/syslinux/mboot.c32 /tftpboot
|
||||
cp /usr/share/syslinux/chain.c32 /tftpboot
|
||||
|
||||
/sbin/service dhcpd start
|
||||
/sbin/service xinetd start
|
||||
/sbin/chkconfig tftp on
|
||||
|
||||
4. Setup default boot menu
|
||||
|
||||
mkdir /tftpboot/pxelinux.cfg
|
||||
touch /tftpboot/pxelinux.cfg/default
|
||||
|
||||
5. Edit the menu `vi /tftpboot/pxelinux.cfg/default`
|
||||
|
||||
default menu.c32
|
||||
prompt 0
|
||||
timeout 15
|
||||
ONTIMEOUT local
|
||||
display boot.msg
|
||||
|
||||
MENU TITLE Main Menu
|
||||
|
||||
LABEL local
|
||||
MENU LABEL Boot local hard drive
|
||||
LOCALBOOT 0
|
||||
|
||||
Now you should have a working PXELINUX setup to image CoreOS nodes. You can verify the services by using VirtualBox locally or with bare metal servers.
|
||||
|
||||
## Adding CoreOS to PXE
|
||||
|
||||
This section describes how to setup the CoreOS images to live alongside a pre-existing PXELINUX environment.
|
||||
|
||||
1. Find or create the TFTP root directory that everything will be based off of.
|
||||
* For this document we will assume `/tftpboot/` is our root directory.
|
||||
2. Once we know and have our tftp root directory we will create a new directory structure for our CoreOS images.
|
||||
3. Download the CoreOS PXE files provided by the CoreOS team.
|
||||
|
||||
MY_TFTPROOT_DIR=/tftpboot
|
||||
mkdir -p $MY_TFTPROOT_DIR/images/coreos/
|
||||
cd $MY_TFTPROOT_DIR/images/coreos/
|
||||
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe.vmlinuz
|
||||
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe.vmlinuz.sig
|
||||
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe_image.cpio.gz
|
||||
wget http://stable.release.core-os.net/amd64-usr/current/coreos_production_pxe_image.cpio.gz.sig
|
||||
gpg --verify coreos_production_pxe.vmlinuz.sig
|
||||
gpg --verify coreos_production_pxe_image.cpio.gz.sig
|
||||
|
||||
4. Edit the menu `vi /tftpboot/pxelinux.cfg/default` again
|
||||
|
||||
default menu.c32
|
||||
prompt 0
|
||||
timeout 300
|
||||
ONTIMEOUT local
|
||||
display boot.msg
|
||||
|
||||
MENU TITLE Main Menu
|
||||
|
||||
LABEL local
|
||||
MENU LABEL Boot local hard drive
|
||||
LOCALBOOT 0
|
||||
|
||||
MENU BEGIN CoreOS Menu
|
||||
|
||||
LABEL coreos-master
|
||||
MENU LABEL CoreOS Master
|
||||
KERNEL images/coreos/coreos_production_pxe.vmlinuz
|
||||
APPEND initrd=images/coreos/coreos_production_pxe_image.cpio.gz cloud-config-url=http://<xxx.xxx.xxx.xxx>/pxe-cloud-config-single-master.yml
|
||||
|
||||
LABEL coreos-slave
|
||||
MENU LABEL CoreOS Slave
|
||||
KERNEL images/coreos/coreos_production_pxe.vmlinuz
|
||||
APPEND initrd=images/coreos/coreos_production_pxe_image.cpio.gz cloud-config-url=http://<xxx.xxx.xxx.xxx>/pxe-cloud-config-slave.yml
|
||||
MENU END
|
||||
|
||||
This configuration file will now boot from local drive but have the option to PXE image CoreOS.
|
||||
|
||||
## DHCP configuration
|
||||
|
||||
This section covers configuring the DHCP server to hand out our new images. In this case we are assuming that there are other servers that will boot alongside other images.
|
||||
|
||||
1. Add the `filename` to the _host_ or _subnet_ sections.
|
||||
|
||||
filename "/tftpboot/pxelinux.0";
|
||||
|
||||
2. At this point we want to make pxelinux configuration files that will be the templates for the different CoreOS deployments.
|
||||
|
||||
subnet 10.20.30.0 netmask 255.255.255.0 {
|
||||
next-server 10.20.30.242;
|
||||
option broadcast-address 10.20.30.255;
|
||||
filename "<other default image>";
|
||||
|
||||
...
|
||||
# http://www.syslinux.org/wiki/index.php/PXELINUX
|
||||
host core_os_master {
|
||||
hardware ethernet d0:00:67:13:0d:00;
|
||||
option routers 10.20.30.1;
|
||||
fixed-address 10.20.30.40;
|
||||
option domain-name-servers 10.20.30.242;
|
||||
filename "/pxelinux.0";
|
||||
}
|
||||
host core_os_slave {
|
||||
hardware ethernet d0:00:67:13:0d:01;
|
||||
option routers 10.20.30.1;
|
||||
fixed-address 10.20.30.41;
|
||||
option domain-name-servers 10.20.30.242;
|
||||
filename "/pxelinux.0";
|
||||
}
|
||||
host core_os_slave2 {
|
||||
hardware ethernet d0:00:67:13:0d:02;
|
||||
option routers 10.20.30.1;
|
||||
fixed-address 10.20.30.42;
|
||||
option domain-name-servers 10.20.30.242;
|
||||
filename "/pxelinux.0";
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
We will be specifying the node configuration later in the guide.
|
||||
|
||||
## Kubernetes
|
||||
|
||||
To deploy our configuration we need to create an `etcd` master. To do so we want to pxe CoreOS with a specific cloud-config.yml. There are two options we have here.
|
||||
1. Is to template the cloud config file and programmatically create new static configs for different cluster setups.
|
||||
2. Have a service discovery protocol running in our stack to do auto discovery.
|
||||
|
||||
This demo we just make a static single `etcd` server to host our Kubernetes and `etcd` master servers.
|
||||
|
||||
Since we are OFFLINE here most of the helping processes in CoreOS and Kubernetes are then limited. To do our setup we will then have to download and serve up our binaries for Kubernetes in our local environment.
|
||||
|
||||
An easy solution is to host a small web server on the DHCP/TFTP host for all our binaries to make them available to the local CoreOS PXE machines.
|
||||
|
||||
To get this up and running we are going to setup a simple `apache` server to serve our binaries needed to bootstrap Kubernetes.
|
||||
|
||||
This is on the PXE server from the previous section:
|
||||
|
||||
rm /etc/httpd/conf.d/welcome.conf
|
||||
cd /var/www/html/
|
||||
wget -O kube-register https://github.com/kelseyhightower/kube-register/releases/download/v0.0.2/kube-register-0.0.2-linux-amd64
|
||||
wget -O setup-network-environment https://github.com/kelseyhightower/setup-network-environment/releases/download/v1.0.0/setup-network-environment
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kubernetes --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kube-apiserver --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kube-controller-manager --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kube-scheduler --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kubectl --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kubecfg --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kubelet --no-check-certificate
|
||||
wget https://storage.googleapis.com/kubernetes-release/release/v0.15.0/bin/linux/amd64/kube-proxy --no-check-certificate
|
||||
wget -O flanneld https://storage.googleapis.com/k8s/flanneld --no-check-certificate
|
||||
|
||||
This sets up our binaries we need to run Kubernetes. This would need to be enhanced to download from the Internet for updates in the future.
|
||||
|
||||
Now for the good stuff!
|
||||
|
||||
## Cloud Configs
|
||||
|
||||
The following config files are tailored for the OFFLINE version of a Kubernetes deployment.
|
||||
|
||||
These are based on the work found here: [master.yml](cloud-configs/master.yaml), [node.yml](cloud-configs/node.yaml)
|
||||
|
||||
To make the setup work, you need to replace a few placeholders:
|
||||
|
||||
- Replace `<PXE_SERVER_IP>` with your PXE server ip address (e.g. 10.20.30.242)
|
||||
- Replace `<MASTER_SERVER_IP>` with the Kubernetes master ip address (e.g. 10.20.30.40)
|
||||
- If you run a private docker registry, replace `rdocker.example.com` with your docker registry dns name.
|
||||
- If you use a proxy, replace `rproxy.example.com` with your proxy server (and port)
|
||||
- Add your own SSH public key(s) to the cloud config at the end
|
||||
|
||||
### master.yml
|
||||
|
||||
On the PXE server make and fill in the variables `vi /var/www/html/coreos/pxe-cloud-config-master.yml`.
|
||||
|
||||
|
||||
#cloud-config
|
||||
---
|
||||
write_files:
|
||||
- path: /opt/bin/waiter.sh
|
||||
owner: root
|
||||
content: |
|
||||
#! /usr/bin/bash
|
||||
until curl http://127.0.0.1:4001/v2/machines; do sleep 2; done
|
||||
- path: /opt/bin/kubernetes-download.sh
|
||||
owner: root
|
||||
permissions: 0755
|
||||
content: |
|
||||
#! /usr/bin/bash
|
||||
/usr/bin/wget -N -P "/opt/bin" "http://<PXE_SERVER_IP>/kubectl"
|
||||
/usr/bin/wget -N -P "/opt/bin" "http://<PXE_SERVER_IP>/kubernetes"
|
||||
/usr/bin/wget -N -P "/opt/bin" "http://<PXE_SERVER_IP>/kubecfg"
|
||||
chmod +x /opt/bin/*
|
||||
- path: /etc/profile.d/opt-path.sh
|
||||
owner: root
|
||||
permissions: 0755
|
||||
content: |
|
||||
#! /usr/bin/bash
|
||||
PATH=$PATH/opt/bin
|
||||
coreos:
|
||||
units:
|
||||
- name: 10-eno1.network
|
||||
runtime: true
|
||||
content: |
|
||||
[Match]
|
||||
Name=eno1
|
||||
[Network]
|
||||
DHCP=yes
|
||||
- name: 20-nodhcp.network
|
||||
runtime: true
|
||||
content: |
|
||||
[Match]
|
||||
Name=en*
|
||||
[Network]
|
||||
DHCP=none
|
||||
- name: get-kube-tools.service
|
||||
runtime: true
|
||||
command: start
|
||||
content: |
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStart=/opt/bin/kubernetes-download.sh
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: setup-network-environment.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Setup Network Environment
|
||||
Documentation=https://github.com/kelseyhightower/setup-network-environment
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/setup-network-environment
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment
|
||||
ExecStart=/opt/bin/setup-network-environment
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: etcd.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=etcd
|
||||
Requires=setup-network-environment.service
|
||||
After=setup-network-environment.service
|
||||
[Service]
|
||||
EnvironmentFile=/etc/network-environment
|
||||
User=etcd
|
||||
PermissionsStartOnly=true
|
||||
ExecStart=/usr/bin/etcd \
|
||||
--name ${DEFAULT_IPV4} \
|
||||
--addr ${DEFAULT_IPV4}:4001 \
|
||||
--bind-addr 0.0.0.0 \
|
||||
--cluster-active-size 1 \
|
||||
--data-dir /var/lib/etcd \
|
||||
--http-read-timeout 86400 \
|
||||
--peer-addr ${DEFAULT_IPV4}:7001 \
|
||||
--snapshot true
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
- name: fleet.socket
|
||||
command: start
|
||||
content: |
|
||||
[Socket]
|
||||
ListenStream=/var/run/fleet.sock
|
||||
- name: fleet.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=fleet daemon
|
||||
Wants=etcd.service
|
||||
After=etcd.service
|
||||
Wants=fleet.socket
|
||||
After=fleet.socket
|
||||
[Service]
|
||||
Environment="FLEET_ETCD_SERVERS=http://127.0.0.1:4001"
|
||||
Environment="FLEET_METADATA=role=master"
|
||||
ExecStart=/usr/bin/fleetd
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
- name: etcd-waiter.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=etcd waiter
|
||||
Wants=network-online.target
|
||||
Wants=etcd.service
|
||||
After=etcd.service
|
||||
After=network-online.target
|
||||
Before=flannel.service
|
||||
Before=setup-network-environment.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/waiter.sh
|
||||
ExecStart=/usr/bin/bash /opt/bin/waiter.sh
|
||||
RemainAfterExit=true
|
||||
Type=oneshot
|
||||
- name: flannel.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Wants=etcd-waiter.service
|
||||
After=etcd-waiter.service
|
||||
Requires=etcd.service
|
||||
After=etcd.service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Description=flannel is an etcd backed overlay network for containers
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/flanneld
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/flanneld
|
||||
ExecStartPre=-/usr/bin/etcdctl mk /coreos.com/network/config '{"Network":"10.100.0.0/16", "Backend": {"Type": "vxlan"}}'
|
||||
ExecStart=/opt/bin/flanneld
|
||||
- name: kube-apiserver.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes API Server
|
||||
Documentation=https://github.com/kubernetes/kubernetes
|
||||
Requires=etcd.service
|
||||
After=etcd.service
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kube-apiserver
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-apiserver
|
||||
ExecStart=/opt/bin/kube-apiserver \
|
||||
--address=0.0.0.0 \
|
||||
--port=8080 \
|
||||
--service-cluster-ip-range=10.100.0.0/16 \
|
||||
--etcd-servers=http://127.0.0.1:4001 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-controller-manager.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Controller Manager
|
||||
Documentation=https://github.com/kubernetes/kubernetes
|
||||
Requires=kube-apiserver.service
|
||||
After=kube-apiserver.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kube-controller-manager
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-controller-manager
|
||||
ExecStart=/opt/bin/kube-controller-manager \
|
||||
--master=127.0.0.1:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-scheduler.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Scheduler
|
||||
Documentation=https://github.com/kubernetes/kubernetes
|
||||
Requires=kube-apiserver.service
|
||||
After=kube-apiserver.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kube-scheduler
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-scheduler
|
||||
ExecStart=/opt/bin/kube-scheduler --master=127.0.0.1:8080
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-register.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Registration Service
|
||||
Documentation=https://github.com/kelseyhightower/kube-register
|
||||
Requires=kube-apiserver.service
|
||||
After=kube-apiserver.service
|
||||
Requires=fleet.service
|
||||
After=fleet.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kube-register
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-register
|
||||
ExecStart=/opt/bin/kube-register \
|
||||
--metadata=role=node \
|
||||
--fleet-endpoint=unix:///var/run/fleet.sock \
|
||||
--healthz-port=10248 \
|
||||
--api-endpoint=http://127.0.0.1:8080
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
||||
ssh_authorized_keys:
|
||||
- ssh-rsa AAAAB3NzaC1yc2EAAAAD...
|
||||
|
||||
|
||||
### node.yml
|
||||
|
||||
On the PXE server make and fill in the variables `vi /var/www/html/coreos/pxe-cloud-config-slave.yml`.
|
||||
|
||||
#cloud-config
|
||||
---
|
||||
write_files:
|
||||
- path: /etc/default/docker
|
||||
content: |
|
||||
DOCKER_EXTRA_OPTS='--insecure-registry="rdocker.example.com:5000"'
|
||||
coreos:
|
||||
units:
|
||||
- name: 10-eno1.network
|
||||
runtime: true
|
||||
content: |
|
||||
[Match]
|
||||
Name=eno1
|
||||
[Network]
|
||||
DHCP=yes
|
||||
- name: 20-nodhcp.network
|
||||
runtime: true
|
||||
content: |
|
||||
[Match]
|
||||
Name=en*
|
||||
[Network]
|
||||
DHCP=none
|
||||
- name: etcd.service
|
||||
mask: true
|
||||
- name: docker.service
|
||||
drop-ins:
|
||||
- name: 50-insecure-registry.conf
|
||||
content: |
|
||||
[Service]
|
||||
Environment="HTTP_PROXY=http://rproxy.example.com:3128/" "NO_PROXY=localhost,127.0.0.0/8,rdocker.example.com"
|
||||
- name: fleet.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=fleet daemon
|
||||
Wants=fleet.socket
|
||||
After=fleet.socket
|
||||
[Service]
|
||||
Environment="FLEET_ETCD_SERVERS=http://<MASTER_SERVER_IP>:4001"
|
||||
Environment="FLEET_METADATA=role=node"
|
||||
ExecStart=/usr/bin/fleetd
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
- name: flannel.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Description=flannel is an etcd backed overlay network for containers
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/flanneld
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/flanneld
|
||||
ExecStart=/opt/bin/flanneld -etcd-endpoints http://<MASTER_SERVER_IP>:4001
|
||||
- name: docker.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
After=flannel.service
|
||||
Wants=flannel.service
|
||||
Description=Docker Application Container Engine
|
||||
Documentation=http://docs.docker.io
|
||||
[Service]
|
||||
EnvironmentFile=-/etc/default/docker
|
||||
EnvironmentFile=/run/flannel/subnet.env
|
||||
ExecStartPre=/bin/mount --make-rprivate /
|
||||
ExecStart=/usr/bin/docker -d --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} -s=overlay -H fd:// ${DOCKER_EXTRA_OPTS}
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
- name: setup-network-environment.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Setup Network Environment
|
||||
Documentation=https://github.com/kelseyhightower/setup-network-environment
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/setup-network-environment
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment
|
||||
ExecStart=/opt/bin/setup-network-environment
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: kube-proxy.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Proxy
|
||||
Documentation=https://github.com/kubernetes/kubernetes
|
||||
Requires=setup-network-environment.service
|
||||
After=setup-network-environment.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kube-proxy
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-proxy
|
||||
ExecStart=/opt/bin/kube-proxy \
|
||||
--etcd-servers=http://<MASTER_SERVER_IP>:4001 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-kubelet.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Kubelet
|
||||
Documentation=https://github.com/kubernetes/kubernetes
|
||||
Requires=setup-network-environment.service
|
||||
After=setup-network-environment.service
|
||||
[Service]
|
||||
EnvironmentFile=/etc/network-environment
|
||||
ExecStartPre=/usr/bin/wget -N -P /opt/bin http://<PXE_SERVER_IP>/kubelet
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kubelet
|
||||
ExecStart=/opt/bin/kubelet \
|
||||
--address=0.0.0.0 \
|
||||
--port=10250 \
|
||||
--hostname-override=${DEFAULT_IPV4} \
|
||||
--api-servers=<MASTER_SERVER_IP>:8080 \
|
||||
--healthz-bind-address=0.0.0.0 \
|
||||
--healthz-port=10248 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
update:
|
||||
group: stable
|
||||
reboot-strategy: off
|
||||
ssh_authorized_keys:
|
||||
- ssh-rsa AAAAB3NzaC1yc2EAAAAD...
|
||||
|
||||
|
||||
## New pxelinux.cfg file
|
||||
|
||||
Create a pxelinux target file for a _slave_ node: `vi /tftpboot/pxelinux.cfg/coreos-node-slave`
|
||||
|
||||
default coreos
|
||||
prompt 1
|
||||
timeout 15
|
||||
|
||||
display boot.msg
|
||||
|
||||
label coreos
|
||||
menu default
|
||||
kernel images/coreos/coreos_production_pxe.vmlinuz
|
||||
append initrd=images/coreos/coreos_production_pxe_image.cpio.gz cloud-config-url=http://<pxe-host-ip>/coreos/pxe-cloud-config-slave.yml console=tty0 console=ttyS0 coreos.autologin=tty1 coreos.autologin=ttyS0
|
||||
|
||||
And one for the _master_ node: `vi /tftpboot/pxelinux.cfg/coreos-node-master`
|
||||
|
||||
default coreos
|
||||
prompt 1
|
||||
timeout 15
|
||||
|
||||
display boot.msg
|
||||
|
||||
label coreos
|
||||
menu default
|
||||
kernel images/coreos/coreos_production_pxe.vmlinuz
|
||||
append initrd=images/coreos/coreos_production_pxe_image.cpio.gz cloud-config-url=http://<pxe-host-ip>/coreos/pxe-cloud-config-master.yml console=tty0 console=ttyS0 coreos.autologin=tty1 coreos.autologin=ttyS0
|
||||
|
||||
## Specify the pxelinux targets
|
||||
|
||||
Now that we have our new targets setup for master and slave we want to configure the specific hosts to those targets. We will do this by using the pxelinux mechanism of setting a specific MAC addresses to a specific pxelinux.cfg file.
|
||||
|
||||
Refer to the MAC address table in the beginning of this guide. Documentation for more details can be found [here](http://www.syslinux.org/wiki/index.php/PXELINUX).
|
||||
|
||||
cd /tftpboot/pxelinux.cfg
|
||||
ln -s coreos-node-master 01-d0-00-67-13-0d-00
|
||||
ln -s coreos-node-slave 01-d0-00-67-13-0d-01
|
||||
ln -s coreos-node-slave 01-d0-00-67-13-0d-02
|
||||
|
||||
|
||||
Reboot these servers to get the images PXEd and ready for running containers!
|
||||
|
||||
## Creating test pod
|
||||
|
||||
Now that the CoreOS with Kubernetes installed is up and running lets spin up some Kubernetes pods to demonstrate the system.
|
||||
|
||||
See [a simple nginx example](../../../docs/user-guide/simple-nginx.html) to try out your new cluster.
|
||||
|
||||
For more complete applications, please look in the [examples directory](../../../examples/).
|
||||
|
||||
## Helping commands for debugging
|
||||
|
||||
List all keys in etcd:
|
||||
|
||||
etcdctl ls --recursive
|
||||
|
||||
List fleet machines
|
||||
|
||||
fleetctl list-machines
|
||||
|
||||
Check system status of services on master:
|
||||
|
||||
systemctl status kube-apiserver
|
||||
systemctl status kube-controller-manager
|
||||
systemctl status kube-scheduler
|
||||
systemctl status kube-register
|
||||
|
||||
Check system status of services on a node:
|
||||
|
||||
systemctl status kube-kubelet
|
||||
systemctl status docker.service
|
||||
|
||||
List Kubernetes
|
||||
|
||||
kubectl get pods
|
||||
kubectl get nodes
|
||||
|
||||
|
||||
Kill all pods:
|
||||
|
||||
for i in `kubectl get pods | awk '{print $1}'`; do kubectl stop pod $i; done
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||||
<!-- TAG IS_VERSIONED -->
|
||||
<!-- END MUNGE: IS_VERSIONED -->
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
#cloud-config
|
||||
|
||||
---
|
||||
write-files:
|
||||
- path: /etc/conf.d/nfs
|
||||
permissions: '0644'
|
||||
content: |
|
||||
OPTS_RPC_MOUNTD=""
|
||||
- path: /opt/bin/wupiao
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
# [w]ait [u]ntil [p]ort [i]s [a]ctually [o]pen
|
||||
[ -n "$1" ] && \
|
||||
until curl -o /dev/null -sIf http://${1}; do \
|
||||
sleep 1 && echo .;
|
||||
done;
|
||||
exit $?
|
||||
|
||||
hostname: master
|
||||
coreos:
|
||||
etcd2:
|
||||
name: master
|
||||
listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
|
||||
advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001
|
||||
initial-cluster-token: k8s_etcd
|
||||
listen-peer-urls: http://$private_ipv4:2380,http://$private_ipv4:7001
|
||||
initial-advertise-peer-urls: http://$private_ipv4:2380
|
||||
initial-cluster: master=http://$private_ipv4:2380
|
||||
initial-cluster-state: new
|
||||
fleet:
|
||||
metadata: "role=master"
|
||||
units:
|
||||
- name: generate-serviceaccount-key.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Generate service-account key file
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStart=/bin/openssl genrsa -out /opt/bin/kube-serviceaccount.key 2048 2>/dev/null
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: setup-network-environment.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Setup Network Environment
|
||||
Documentation=https://github.com/kelseyhightower/setup-network-environment
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/setup-network-environment -z /opt/bin/setup-network-environment https://github.com/kelseyhightower/setup-network-environment/releases/download/v1.0.0/setup-network-environment
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment
|
||||
ExecStart=/opt/bin/setup-network-environment
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: fleet.service
|
||||
command: start
|
||||
- name: flanneld.service
|
||||
command: start
|
||||
drop-ins:
|
||||
- name: 50-network-config.conf
|
||||
content: |
|
||||
[Unit]
|
||||
Requires=etcd2.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{"Network":"10.244.0.0/16", "Backend": {"Type": "vxlan"}}'
|
||||
- name: docker.service
|
||||
command: start
|
||||
- name: kube-apiserver.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes API Server
|
||||
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
|
||||
Requires=setup-network-environment.service etcd2.service generate-serviceaccount-key.service
|
||||
After=setup-network-environment.service etcd2.service generate-serviceaccount-key.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/network-environment
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/kube-apiserver -z /opt/bin/kube-apiserver https://storage.googleapis.com/kubernetes-release/release/v1.0.3/bin/linux/amd64/kube-apiserver
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-apiserver
|
||||
ExecStartPre=/opt/bin/wupiao 127.0.0.1:2379/v2/machines
|
||||
ExecStart=/opt/bin/kube-apiserver \
|
||||
--service-account-key-file=/opt/bin/kube-serviceaccount.key \
|
||||
--service-account-lookup=false \
|
||||
--admission-control=NamespaceLifecycle,NamespaceAutoProvision,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota \
|
||||
--runtime-config=api/v1 \
|
||||
--allow-privileged=true \
|
||||
--insecure-bind-address=0.0.0.0 \
|
||||
--insecure-port=8080 \
|
||||
--kubelet-https=true \
|
||||
--secure-port=6443 \
|
||||
--service-cluster-ip-range=10.100.0.0/16 \
|
||||
--etcd-servers=http://127.0.0.1:2379 \
|
||||
--public-address-override=${DEFAULT_IPV4} \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-controller-manager.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Controller Manager
|
||||
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
|
||||
Requires=kube-apiserver.service
|
||||
After=kube-apiserver.service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/kube-controller-manager -z /opt/bin/kube-controller-manager https://storage.googleapis.com/kubernetes-release/release/v1.0.3/bin/linux/amd64/kube-controller-manager
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-controller-manager
|
||||
ExecStart=/opt/bin/kube-controller-manager \
|
||||
--service-account-private-key-file=/opt/bin/kube-serviceaccount.key \
|
||||
--master=127.0.0.1:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-scheduler.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Scheduler
|
||||
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
|
||||
Requires=kube-apiserver.service
|
||||
After=kube-apiserver.service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/kube-scheduler -z /opt/bin/kube-scheduler https://storage.googleapis.com/kubernetes-release/release/v1.0.3/bin/linux/amd64/kube-scheduler
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-scheduler
|
||||
ExecStart=/opt/bin/kube-scheduler --master=127.0.0.1:8080
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
update:
|
||||
group: alpha
|
||||
reboot-strategy: off
|
||||
@@ -0,0 +1,98 @@
|
||||
#cloud-config
|
||||
write-files:
|
||||
- path: /opt/bin/wupiao
|
||||
permissions: '0755'
|
||||
content: |
|
||||
#!/bin/bash
|
||||
# [w]ait [u]ntil [p]ort [i]s [a]ctually [o]pen
|
||||
[ -n "$1" ] && [ -n "$2" ] && while ! curl --output /dev/null \
|
||||
--silent --head --fail \
|
||||
http://${1}:${2}; do sleep 1 && echo -n .; done;
|
||||
exit $?
|
||||
coreos:
|
||||
etcd2:
|
||||
listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
|
||||
advertise-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001
|
||||
initial-cluster: master=http://<master-private-ip>:2380
|
||||
proxy: on
|
||||
fleet:
|
||||
metadata: "role=node"
|
||||
units:
|
||||
- name: fleet.service
|
||||
command: start
|
||||
- name: flanneld.service
|
||||
command: start
|
||||
drop-ins:
|
||||
- name: 50-network-config.conf
|
||||
content: |
|
||||
[Unit]
|
||||
Requires=etcd2.service
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{"Network":"10.244.0.0/16", "Backend": {"Type": "vxlan"}}'
|
||||
- name: docker.service
|
||||
command: start
|
||||
- name: setup-network-environment.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Setup Network Environment
|
||||
Documentation=https://github.com/kelseyhightower/setup-network-environment
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/mkdir -p /opt/bin
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/setup-network-environment -z /opt/bin/setup-network-environment https://github.com/kelseyhightower/setup-network-environment/releases/download/v1.0.0/setup-network-environment
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/setup-network-environment
|
||||
ExecStart=/opt/bin/setup-network-environment
|
||||
RemainAfterExit=yes
|
||||
Type=oneshot
|
||||
- name: kube-proxy.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Proxy
|
||||
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
|
||||
Requires=setup-network-environment.service
|
||||
After=setup-network-environment.service
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/kube-proxy -z /opt/bin/kube-proxy https://storage.googleapis.com/kubernetes-release/release/v1.0.3/bin/linux/amd64/kube-proxy
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kube-proxy
|
||||
# wait for kubernetes master to be up and ready
|
||||
ExecStartPre=/opt/bin/wupiao <master-private-ip> 8080
|
||||
ExecStart=/opt/bin/kube-proxy \
|
||||
--master=<master-private-ip>:8080 \
|
||||
--logtostderr=true
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
- name: kube-kubelet.service
|
||||
command: start
|
||||
content: |
|
||||
[Unit]
|
||||
Description=Kubernetes Kubelet
|
||||
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
|
||||
Requires=setup-network-environment.service
|
||||
After=setup-network-environment.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/etc/network-environment
|
||||
ExecStartPre=/usr/bin/curl -L -o /opt/bin/kubelet -z /opt/bin/kubelet https://storage.googleapis.com/kubernetes-release/release/v1.0.3/bin/linux/amd64/kubelet
|
||||
ExecStartPre=/usr/bin/chmod +x /opt/bin/kubelet
|
||||
# wait for kubernetes master to be up and ready
|
||||
ExecStartPre=/opt/bin/wupiao <master-private-ip> 8080
|
||||
ExecStart=/opt/bin/kubelet \
|
||||
--address=0.0.0.0 \
|
||||
--port=10250 \
|
||||
--hostname-override=${DEFAULT_IPV4} \
|
||||
--api-servers=<master-private-ip>:8080 \
|
||||
--allow-privileged=true \
|
||||
--logtostderr=true \
|
||||
--cadvisor-port=4194 \
|
||||
--healthz-bind-address=0.0.0.0 \
|
||||
--healthz-port=10248
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
update:
|
||||
group: alpha
|
||||
reboot-strategy: off
|
||||
@@ -0,0 +1,248 @@
|
||||
---
|
||||
layout: docwithnav
|
||||
title: "CoreOS Multinode Cluster"
|
||||
---
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
# CoreOS Multinode Cluster
|
||||
|
||||
Use the [master.yaml](cloud-configs/master.yaml) and [node.yaml](cloud-configs/node.yaml) cloud-configs to provision a multi-node Kubernetes cluster.
|
||||
|
||||
> **Attention**: This requires at least CoreOS version **[695.0.0][coreos695]**, which includes `etcd2`.
|
||||
|
||||
[coreos695]: https://coreos.com/releases/#695.0.0
|
||||
|
||||
## Overview
|
||||
|
||||
* Provision the master node
|
||||
* Capture the master node private IP address
|
||||
* Edit node.yaml
|
||||
* Provision one or more worker nodes
|
||||
|
||||
### AWS
|
||||
|
||||
*Attention:* Replace `<ami_image_id>` below for a [suitable version of CoreOS image for AWS](https://coreos.com/docs/running-coreos/cloud-providers/ec2/).
|
||||
|
||||
#### Provision the Master
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
aws ec2 create-security-group --group-name kubernetes --description "Kubernetes Security Group"
|
||||
aws ec2 authorize-security-group-ingress --group-name kubernetes --protocol tcp --port 22 --cidr 0.0.0.0/0
|
||||
aws ec2 authorize-security-group-ingress --group-name kubernetes --protocol tcp --port 80 --cidr 0.0.0.0/0
|
||||
aws ec2 authorize-security-group-ingress --group-name kubernetes --source-security-group-name kubernetes
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
aws ec2 run-instances \
|
||||
--image-id <ami_image_id> \
|
||||
--key-name <keypair> \
|
||||
--region us-west-2 \
|
||||
--security-groups kubernetes \
|
||||
--instance-type m3.medium \
|
||||
--user-data file://master.yaml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Capture the private IP address
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
aws ec2 describe-instances --instance-id <master-instance-id>
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Edit node.yaml
|
||||
|
||||
Edit `node.yaml` and replace all instances of `<master-private-ip>` with the private IP address of the master node.
|
||||
|
||||
#### Provision worker nodes
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
aws ec2 run-instances \
|
||||
--count 1 \
|
||||
--image-id <ami_image_id> \
|
||||
--key-name <keypair> \
|
||||
--region us-west-2 \
|
||||
--security-groups kubernetes \
|
||||
--instance-type m3.medium \
|
||||
--user-data file://node.yaml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
### Google Compute Engine (GCE)
|
||||
|
||||
*Attention:* Replace `<gce_image_id>` below for a [suitable version of CoreOS image for Google Compute Engine](https://coreos.com/docs/running-coreos/cloud-providers/google-compute-engine/).
|
||||
|
||||
#### Provision the Master
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
gcloud compute instances create master \
|
||||
--image-project coreos-cloud \
|
||||
--image <gce_image_id> \
|
||||
--boot-disk-size 200GB \
|
||||
--machine-type n1-standard-1 \
|
||||
--zone us-central1-a \
|
||||
--metadata-from-file user-data=master.yaml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Capture the private IP address
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
gcloud compute instances list
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Edit node.yaml
|
||||
|
||||
Edit `node.yaml` and replace all instances of `<master-private-ip>` with the private IP address of the master node.
|
||||
|
||||
#### Provision worker nodes
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
gcloud compute instances create node1 \
|
||||
--image-project coreos-cloud \
|
||||
--image <gce_image_id> \
|
||||
--boot-disk-size 200GB \
|
||||
--machine-type n1-standard-1 \
|
||||
--zone us-central1-a \
|
||||
--metadata-from-file user-data=node.yaml
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Establish network connectivity
|
||||
|
||||
Next, setup an ssh tunnel to the master so you can run kubectl from your local host.
|
||||
In one terminal, run `gcloud compute ssh master --ssh-flag="-L 8080:127.0.0.1:8080"` and in a second
|
||||
run `gcloud compute ssh master --ssh-flag="-R 8080:127.0.0.1:8080"`.
|
||||
|
||||
### OpenStack
|
||||
|
||||
These instructions are for running on the command line. Most of this you can also do through the Horizon dashboard.
|
||||
These instructions were tested on the Ice House release on a Metacloud distribution of OpenStack but should be similar if not the same across other versions/distributions of OpenStack.
|
||||
|
||||
#### Make sure you can connect with OpenStack
|
||||
|
||||
Make sure the environment variables are set for OpenStack such as:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
OS_TENANT_ID
|
||||
OS_PASSWORD
|
||||
OS_AUTH_URL
|
||||
OS_USERNAME
|
||||
OS_TENANT_NAME
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
Test this works with something like:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
nova list
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
#### Get a Suitable CoreOS Image
|
||||
|
||||
You'll need a [suitable version of CoreOS image for OpenStack](https://coreos.com/os/docs/latest/booting-on-openstack.html)
|
||||
Once you download that, upload it to glance. An example is shown below:
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
glance image-create --name CoreOS723 \
|
||||
--container-format bare --disk-format qcow2 \
|
||||
--file coreos_production_openstack_image.img \
|
||||
--is-public True
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Create security group
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
nova secgroup-create kubernetes "Kubernetes Security Group"
|
||||
nova secgroup-add-rule kubernetes tcp 22 22 0.0.0.0/0
|
||||
nova secgroup-add-rule kubernetes tcp 80 80 0.0.0.0/0
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
#### Provision the Master
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
nova boot \
|
||||
--image <image_name> \
|
||||
--key-name <my_key> \
|
||||
--flavor <flavor id> \
|
||||
--security-group kubernetes \
|
||||
--user-data files/master.yaml \
|
||||
kube-master
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
```<image_name>``` is the CoreOS image name. In our example we can use the image we created in the previous step and put in 'CoreOS723'
|
||||
|
||||
```<my_key>``` is the keypair name that you already generated to access the instance.
|
||||
|
||||
```<flavor_id>``` is the flavor ID you use to size the instance. Run ```nova flavor-list``` to get the IDs. 3 on the system this was tested with gives the m1.large size.
|
||||
|
||||
The important part is to ensure you have the files/master.yml as this is what will do all the post boot configuration. This path is relevant so we are assuming in this example that you are running the nova command in a directory where there is a subdirectory called files that has the master.yml file in it. Absolute paths also work.
|
||||
|
||||
Next, assign it a public IP address:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
nova floating-ip-list
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
Get an IP address that's free and run:
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
nova floating-ip-associate kube-master <ip address>
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
where ```<ip address>``` is the IP address that was available from the ```nova floating-ip-list``` command.
|
||||
|
||||
#### Provision Worker Nodes
|
||||
|
||||
Edit ```node.yaml``` and replace all instances of ```<master-private-ip>``` with the private IP address of the master node. You can get this by running ```nova show kube-master``` assuming you named your instance kube master. This is not the floating IP address you just assigned it.
|
||||
|
||||
{% highlight sh %}
|
||||
{% raw %}
|
||||
nova boot \
|
||||
--image <image_name> \
|
||||
--key-name <my_key> \
|
||||
--flavor <flavor id> \
|
||||
--security-group kubernetes \
|
||||
--user-data files/node.yaml \
|
||||
minion01
|
||||
{% endraw %}
|
||||
{% endhighlight %}
|
||||
|
||||
This is basically the same as the master nodes but with the node.yaml post-boot script instead of the master.
|
||||
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: IS_VERSIONED -->
|
||||
<!-- TAG IS_VERSIONED -->
|
||||
<!-- END MUNGE: IS_VERSIONED -->
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
||||
Reference in New Issue
Block a user