このエントリはKubernetesアドベントカレンダー2014の9日目です。
いよいよ小規模なKubetnetesクラスタを構築してみます。
構成
プロダクトバージョン
- VirtualBox
- CentOS7
- etcd 0.4.6
- flannel 0.1.0
- Kubernetes 0.5.3
ネットワーク
- eth0(NAT): 10.0.2.0/24
- eth1(Hostonly): 172.16.0.0/16
- flannel全体: 172.17.0.0/16
- Kubernetes: 172.18.0.0/16
サーバ
- Master 1台: Kubernetes(kube-apiserver, kube-controller-manager, kube-scheduler, kubelet), docker, etcd, flannel
- master01: 172.16.1.1
- Minion 3台: Kubernetes(kubelet, kube-proxy), docker, etcd, flannel
- minion01: 172.16.2.1
- minion02: 172.16.2.2
- minion03: 172.16.2.3
構築
段取りとしては、
- まずetcd+flannel+dockerなクラスタを組む
- Kubernetesをインストール
です。
構築1. etcd+flannel+dockerなクラスタを組む
Master
まずはホスト名を設定(わけわかけめになるのは困る)
hostnamectl set-hostname master01
reboot
ネットワーク設定
firewall-cmd --set-default-zone=trusted
ETH1_UUID=$(nmcli --fields uuid,device con show | grep -w eth1 | awk '{print $1}')
nmcli con mod ${ETH1_UUID:?} ipv4.method manual ipv4.addresses "172.16.1.1/16"
nmcli con up ${ETH1_UUID:?}
etcd
, etcdctl
, flannel
をインストール
yum -y install golang
yum -y install git
git clone https://github.com/coreos/etcd.git /opt/etcd
cd /opt/etcd
git checkout v0.4.6
./build
cp bin/etcd /usr/local/sbin/.
git clone https://github.com/coreos/etcdctl.git /opt/etcdctl
cd /opt/etcdctl
git checkout v0.4.5
./build
cp bin/etcdctl /usr/local/sbin/.
yum -y install kernel-headers
git clone https://github.com/coreos/flannel.git /opt/flannel
cd /opt/flannel
git checkout v0.1.0
./build
cp bin/flanneld /usr/local/sbin/.
etcd
を起動し、 etcdctl
で設定投入。 flannel
を起動して docker
を起動。
ここまでは昨日とほぼ同じですね。
etcd -name=master01 -data-dir=/tmp/etcd -addr=172.16.1.1:4001 -peer-addr=172.16.1.1:7001 >/tmp/etcd.log 2>&1 &
etcdctl mk /coreos.com/network/config '{"Network":"172.17.0.0/16"}'
flanneld -ip-masq=true -etcd-endpoint=http://172.16.1.1:4001 -iface=eth1 >/tmp/flanneld.log 2>&1 &
yum -y install docker
sed -i -r 's@^(ExecStart=.*)@EnvironmentFile=-/run/flannel/subnet.env\n\1 --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}@' /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl start docker.service
Minion(各Minionで実施)
こちらも昨日とほぼ同じです。 まずはホスト名を設定(わけわかけめになるのは困る)
hostnamectl set-hostname minion01
reboot
ネットワーク設定(IPアドレスはホストごとに変えてくださいね)
firewall-cmd --set-default-zone=trusted
ETH1_UUID=$(nmcli --fields uuid,device con show | grep -w eth1 | awk '{print $1}')
nmcli con mod ${ETH1_UUID:?} ipv4.method manual ipv4.addresses "172.16.2.1/16"
nmcli con up ${ETH1_UUID:?}
etcd
, etcdctl
, flannel
をインストール。Masterでビルド済みのものをコピーしてもよいです。
yum -y install golang
yum -y install git
git clone https://github.com/coreos/etcd.git /opt/etcd
cd /opt/etcd
git checkout v0.4.6
./build
cp bin/etcd /usr/local/sbin/.
git clone https://github.com/coreos/etcdctl.git /opt/etcdctl
cd /opt/etcdctl
git checkout v0.4.5
./build
cp bin/etcdctl /usr/local/sbin/.
yum -y install kernel-headers
git clone https://github.com/coreos/flannel.git /opt/flannel
cd /opt/flannel
git checkout v0.1.0
./build
cp bin/flanneld /usr/local/sbin/.
etcd
を起動し、 flannel
を起動して docker
を起動。
etcd
はMasterと協調するようにします。
MYIP=$(ip addr show eth1 | grep -w inet | awk '{print $2}' | cut -d / -f 1)
etcd -name=${HOSTNAME:?} -data-dir=/tmp/etcd -addr=${MYIP:?}:4001 -peer-addr=${MYIP:?}:7001 -peers=172.16.1.1:7001 >/tmp/etcd.log 2>&1 &
flanneld -ip-masq=true -etcd-endpoint=http://localhost:4001 -iface=eth1 >/tmp/flanneld.log 2>&1 &
yum -y install docker
sed -i -r 's@^(ExecStart=.*)@EnvironmentFile=-/run/flannel/subnet.env\n\1 --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}@' /usr/lib/systemd/system/docker.service
systemctl daemon-reload
systemctl start docker.service
これで準備は完了です。 etcdにクラスタに参加しているメンバーを問い合わせるときちんと4台出てきます。
[root@master01 kubernetes]# curl http://localhost:4001/v2/machines
http://172.16.1.1:4001, http://172.16.2.2:4001, http://172.16.2.1:4001, http://172.16.2.3:4001
リーダーも決まっています。
[root@master01 kubernetes]# curl http://localhost:4001/v2/leader
http://172.16.1.1:7001
きちんと全台のdocker0が異なるネットワークアドレス帯を持っています。
[root@master01 kubernetes]# ip addr show docker0
8: docker0: mtu 1500 qdisc noqueue state DOWN
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.15.1/24 scope global docker0
valid_lft forever preferred_lft forever
[root@minion01 flannel]# ip addr show docker0
5: docker0: mtu 1500 qdisc noqueue state DOWN
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.84.1/24 scope global docker0
valid_lft forever preferred_lft forever
[root@minion02 flannel]# ip addr show docker0
5: docker0: mtu 1500 qdisc noqueue state DOWN
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.99.1/24 scope global docker0
valid_lft forever preferred_lft forever
5: docker0: mtu 1500 qdisc noqueue state DOWN
link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
inet 172.17.62.1/24 scope global docker0
valid_lft forever preferred_lft forever
構築2. Kubernetes
次はKubernetesをインストールしましょう。
Master
ドキュメントに倣い、Masterでは kube-apiserver
, kube-controller-manager
, kube-scheduler
, kubelet
を起動します。
まずはKubernetesをダウンロードして配置します。
curl -L https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.5.3/kubernetes.tar.gz | tar zxf - -C /opt
tar zxf /opt/kubernetes/server/kubernetes-server-linux-amd64.tar.gz -C /tmp
cp /tmp/kubernetes/server/bin/* /usr/local/sbin/.
kube-apiserver
kube-apiserver
を起動します。
-address
: HTTP APIの待ち受けアドレス-port
: HTTP APIの待ち受けポート-etcd-servers
: etcdのエンドポイント(,区切りで複数指定可能)-portal_net
: KubernetesがService
のエンドポイントに割り当てるIPアドレスのネットワークアドレス帯(他のネットワークアドレス帯と重複しないように設定する)-cors_allowed_origins
: Cross Origin Resource Sharingの許可Originのパターン(正規表現。,区切りで複数指定可能)-v
: ログレベル
kube-apiserver \
-address=172.16.1.1 \
-port=8080 \
-etcd_servers='http://172.16.1.1:4001,http://172.16.2.1:4001,http://172.16.2.2:4001,http://172.16.2.3:4001' \
-portal_net=172.18.0.0/16 \
-cors_allowed_origins='/127.0.0.1(:[0-9]+)?$,/localhost(:[0-9]+)?$,/172.16.[0-9]+.[0-9]+$' \
-v=3 >/tmp/kube-apiserver.log 2>&1 &
kube-controller-manager
次は kube-controller-manager
です。
-machines
: クラスタに参加するminion-master
: kube-apiserverのエンドポイント-v
: ログレベル
kube-controller-manager \
-machines='172.16.2.1,172.16.2.2,172.16.2.3' \
-master='172.16.1.1:8080' \
-v=3 >/tmp/kube-controller-manager.log 2>&1 &
kube-scheduler
次は kube-scheduler
です。
-master
: kube-apiserverのエンドポイント-v
: ログレベル
kube-scheduler \
-master='http://172.16.1.1:8080' \
-v=3 >/tmp/kube-scheduler.log 2>&1 &
kubelet
次は kubelet
です。
-address
: kubeletの待ち受けアドレス(default: 127.0.0.1)-port
: kubeletの待ち受けポート(default: 10250)-etcd-servers
: etcdのエンドポイント(,区切りで複数指定可能)-v
: ログレベル
kubelet \
-address=172.16.1.1 \
-etcd_servers='http://172.16.1.1:4001,http://172.16.2.1:4001,http://172.16.2.2:4001,http://172.16.2.3:4001' \
-v=3 >/tmp/kubelet.log 2>&1 &
Minion(各Minionで実施)
ドキュメントに倣い、Minionでは kubelet
, kube-proxy
を起動します。
まずはKubernetesをダウンロードして配置します。
curl -L https://github.com/GoogleCloudPlatform/kubernetes/releases/download/v0.5.3/kubernetes.tar.gz | tar zxf - -C /opt
tar zxf /opt/kubernetes/server/kubernetes-server-linux-amd64.tar.gz -C /tmp
cp /tmp/kubernetes/server/bin/* /usr/local/sbin/.
kubelet
まずは kubelet
です。
-address
: kubeletの待ち受けアドレス(default: 127.0.0.1)-port
: kubeletの待ち受けポート(default: 10250)-hostname_override
: ホスト名。マスターが認識しているホスト名と整合していないとkubeletがPodの割り当てを自分宛と解釈できず無視してしまうので注意(default: ホスト名)-etcd-servers
: etcdのエンドポイント(,区切りで複数指定可能)-v
: ログレベル
MYIP=$(ip addr show eth1 | grep -w inet | awk '{print $2}' | cut -d / -f 1)
kubelet \
-address=${MYIP:?} \
-hostname_override=${MYIP:?} \
-etcd_servers='http://172.16.1.1:4001,http://172.16.2.1:4001,http://172.16.2.2:4001,http://172.16.2.3:4001' \
-v=3 >/tmp/kubelet.log 2>&1 &
kube-proxy
次は kube-proxy
です。
-master
: kube-apiserverのエンドポイント-v
: ログレベル
kube-proxy \
-master='http://172.16.1.1:8080' \
-v=3 >/tmp/kube-proxy.log 2>&1 &
Kubernetesを使ってみる
kubecfg
または kubectl
で操作します。
-h
で kube-apiserver
のエンドポイントを指定します。
[root@master01 kubernetes]# kubecfg -h http://172.16.1.1:8080 list minions
Minion identifier
----------
172.16.2.1
172.16.2.2
172.16.2.3
[root@master01 kubernetes]# kubecfg -h http://172.16.1.1:8080 list pods
Name Image(s) Host Labels Status
---------- ---------- ---------- ---------- ----------
[root@master01 kubernetes]# kubecfg -h http://172.16.1.1:8080 list services
Name Labels Selector IP Port
---------- ---------- ---------- ---------- ----------
kubernetes-ro component=apiserver,provider=kubernetes 172.18.19.79 80
kubernetes component=apiserver,provider=kubernetes 172.18.208.82 443
[root@master01 kubernetes]# kubecfg -h http://172.16.1.1:8080 list replicationControllers
Name Image(s) Selector Replicas
---------- ---------- ---------- ----------
kubectl
の場合は -s
で kube-apiserver
のエンドポイントを指定します。
[root@master01 kubernetes]# kubectl get minions -s http://172.16.1.1:8080
NAME
172.16.2.3
172.16.2.1
172.16.2.2
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080
NAME IMAGE(S) HOST LABELS STATUS
[root@master01 kubernetes]# kubectl get services -s http://172.16.1.1:8080
NAME LABELS SELECTOR IP PORT
kubernetes component=apiserver,provider=kubernetes 172.18.208.82 443
kubernetes-ro component=apiserver,provider=kubernetes 172.18.19.79 80
[root@master01 kubernetes]# kubectl get replicationControllers -s http://172.16.1.1:8080
NAME IMAGE(S) SELECTOR REPLICAS
guestbook example
それでは恒例のguestbook exampleを適用してみましょう。
kubectl create -f /opt/kubernetes/examples/guestbook/redis-master.json pods -s http://172.16.1.1:8080
kubectl create -f /opt/kubernetes/examples/guestbook/redis-master-service.json services -s http://172.16.1.1:8080
kubectl create -f /opt/kubernetes/examples/guestbook/redis-slave-controller.json create replicationControllers -s http://172.16.1.1:8080
kubectl create -f /opt/kubernetes/examples/guestbook/redis-slave-service.json create services -s http://172.16.1.1:8080
kubectl create -f /opt/kubernetes/examples/guestbook/frontend-controller.json create replicationControllers -s http://172.16.1.1:8080
起動成功すると以下のようにずらっと Pod
、 Service
、 ReplicationController
ができます。
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080
NAME IMAGE(S) HOST LABELS STATUS
redis-master dockerfile/redis 172.16.2.2/ name=redis-master Running
5a7b25b6-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.3/ name=redisslave,uses=redis-master Running
5a7c7887-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.1/ name=redisslave,uses=redis-master Running
64fd69ff-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.2/ name=frontend,uses=redisslave,redis-master Running
64fdf914-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.1/ name=frontend,uses=redisslave,redis-master Running
64fe0237-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.3/ name=frontend,uses=redisslave,redis-master Running
(reverse-i-search)`ger ': kube-controller-mana^Cr -h
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080
NAME IMAGE(S) HOST LABELS STATUS
64fd69ff-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.2/ name=frontend,uses=redisslave,redis-master Running
64fdf914-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.1/ name=frontend,uses=redisslave,redis-master Running
64fe0237-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.3/ name=frontend,uses=redisslave,redis-master Running
redis-master dockerfile/redis 172.16.2.2/ name=redis-master Running
5a7b25b6-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.3/ name=redisslave,uses=redis-master Running
5a7c7887-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.1/ name=redisslave,uses=redis-master Running
[root@master01 kubernetes]# kubectl get services -s http://172.16.1.1:8080
NAME LABELS SELECTOR IP PORT
redisslave name=redisslave name=redisslave 172.18.63.255 6379
kubernetes component=apiserver,provider=kubernetes 172.18.208.82 443
kubernetes-ro component=apiserver,provider=kubernetes 172.18.19.79 80
redis-master name=redis-master name=redis-master 172.18.100.193 6379
[root@master01 kubernetes]# kubectl get replicationControllers -s http://172.16.1.1:8080
NAME IMAGE(S) SELECTOR REPLICAS
redisSlaveController brendanburns/redis-slave name=redisslave 2
frontendController brendanburns/php-redis name=frontend 3
障害を起こしてみる その1: コンテナを止めてみる
突然ですがredis-masterコンテナを停止してみましょう。
[root@master01 kubernetes]# kubectl get minions -s http://172.16.1.1:8080 | tail -n +2 | sort
172.16.2.1
172.16.2.2
172.16.2.3
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080 | tail -n +2 | sort -k 2,3
redis-master dockerfile/redis 172.16.2.2/ name=redis-master Running
64fdf914-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.1/ name=frontend,uses=redisslave,redis-master Running
35d5a43d-7d47-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.2/ name=frontend,uses=redisslave,redis-master Running
64fe0237-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.3/ name=frontend,uses=redisslave,redis-master Running
5a7c7887-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.1/ name=redisslave,uses=redis-master Running
5a7b25b6-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.3/ name=redisslave,uses=redis-master Running
[root@master01 kubernetes]# kubectl get services -s http://172.16.1.1:8080 | tail -n +2 | sort
kubernetes component=apiserver,provider=kubernetes 172.18.208.82 443
kubernetes-ro component=apiserver,provider=kubernetes 172.18.19.79 80
redis-master name=redis-master name=redis-master 172.18.100.193 6379
redisslave name=redisslave name=redisslave 172.18.63.255 6379
おもむろにコンテナを止めます。
[root@minion02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
50fc7a1b4023 brendanburns/php-redis:latest "/bin/sh -c /run.sh" 6 minutes ago Up 6 minutes k8s_php-redis.ff90cc2a_35d5a43d-7d47-11e4-9e45-0800272a0168.default.etcd_35d5ab2b-7d47-11e4-9e45-0800272a0168_4cd76015
d6c42d94a79e kubernetes/pause:latest "/pause" 6 minutes ago Up 6 minutes 0.0.0.0:8000->80/tcp k8s_net.163f8d3c_35d5a43d-7d47-11e4-9e45-0800272a0168.default.etcd_35d5ab2b-7d47-11e4-9e45-0800272a0168_2e0d087b
edf502b0f958 dockerfile/redis:latest "redis-server /etc/r 28 minutes ago Up 28 minutes k8s_master.b57aab79_redis-master.default.etcd_4161f49a-7d45-11e4-9e45-0800272a0168_3fb4bfcb
02457cc07656 kubernetes/pause:latest "/pause" 28 minutes ago Up 28 minutes 0.0.0.0:6379->6379/tcp k8s_net.7168dbe_redis-master.default.etcd_4161f49a-7d45-11e4-9e45-0800272a0168_8681a0d5
[root@minion02 ~]# docker kill edf502b0f958
edf502b0f958
ちょっと待ってから docker ps
してみると…
[root@minion02 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a2f0299f7f48 dockerfile/redis:latest "redis-server /etc/r About a minute ago Up About a minute k8s_master.b57aab79_redis-master.default.etcd_4161f49a-7d45-11e4-9e45-0800272a0168_04a99fef
50fc7a1b4023 brendanburns/php-redis:latest "/bin/sh -c /run.sh" 7 minutes ago Up 7 minutes k8s_php-redis.ff90cc2a_35d5a43d-7d47-11e4-9e45-0800272a0168.default.etcd_35d5ab2b-7d47-11e4-9e45-0800272a0168_4cd76015
d6c42d94a79e kubernetes/pause:latest "/pause" 7 minutes ago Up 7 minutes 0.0.0.0:8000->80/tcp k8s_net.163f8d3c_35d5a43d-7d47-11e4-9e45-0800272a0168.default.etcd_35d5ab2b-7d47-11e4-9e45-0800272a0168_2e0d087b
02457cc07656 kubernetes/pause:latest "/pause" 29 minutes ago Up 29 minutes 0.0.0.0:6379->6379/tcp k8s_net.7168dbe_redis-master.default.etcd_4161f49a-7d45-11e4-9e45-0800272a0168_8681a0d5
再度起動しています!すばらしい!
障害を起こしてみる その2: コンテナを止めてみる
突然ですがminion03サーバを停止してみましょう。
[root@master01 kubernetes]# kubectl get minions -s http://172.16.1.1:8080 | tail -n +2 | sort
172.16.2.1
172.16.2.2
172.16.2.3
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080 | tail -n +2 | sort -k 2,3
redis-master dockerfile/redis 172.16.2.2/ name=redis-master Running
64fdf914-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.1/ name=frontend,uses=redisslave,redis-master Running
64fd69ff-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.2/ name=frontend,uses=redisslave,redis-master Running
64fe0237-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.3/ name=frontend,uses=redisslave,redis-master Running
5a7c7887-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.1/ name=redisslave,uses=redis-master Running
5a7b25b6-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.3/ name=redisslave,uses=redis-master Running
止めます
[root@minion03 ~]# shutdown -h now
ちょっと待ちますと…
[root@master01 kubernetes]# kubectl get minions -s http://172.16.1.1:8080 | tail -n +2 | sort
172.16.2.1
172.16.2.2
[root@master01 kubernetes]# kubectl get pods -s http://172.16.1.1:8080 | tail -n +2 | sort -k 2,3
redis-master dockerfile/redis 172.16.2.2/ name=redis-master Running
64fdf914-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.1/ name=frontend,uses=redisslave,redis-master Running
64fd69ff-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.2/ name=frontend,uses=redisslave,redis-master Running
64fe0237-7d45-11e4-9e45-0800272a0168 brendanburns/php-redis 172.16.2.3/ name=frontend,uses=redisslave,redis-master Failed
5a7c7887-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.1/ name=redisslave,uses=redis-master Running
23f15d17-7d47-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.2/ name=redisslave,uses=redis-master Running
5a7b25b6-7d45-11e4-9e45-0800272a0168 brendanburns/redis-slave 172.16.2.3/ name=redisslave,uses=redis-master Failed
障害を検出してます。 他ホストにコンテナを移動はしてくれないようです。 機能がないのか設定が足りないのかは未確認
おまけ
今回は全部心のこもった手作業+手動起動なので敢えてdockerは自動起動にしていませんが、 依存関係をsystemdできちんと設定すれば自動起動できますはずです。
おまけ2
試行錯誤してる中で docker pull
待ちが長くてイライラするときは、あらかじめ以下のイメージをpullしておきましょう。
docker pull kubernetes/pause:latest
docker pull dockerfile/redis:latest
docker pull brendanburns/redis-slave:latest
docker pull brendanburns/php-redis:latest