HEARTBEATS

Kubernetesを自分で動かす@SoftLayer

   

こんにちは。CTOの馬場です。

このエントリは 1枚目 SoftLayer Advent Calendar 2014 の2日目です。

Google Container Engine (GKE) が花盛りですが、インフラエンジニアたるもの自分でも動かしてみたいですよね。とはいえ基盤と環境を用意するのは大変。

というわけで基盤と環境の部分はSoftLayerを使って代替することにして、SoftLayer上でKubernetes(k8s)を動かしてみます。

SoftLayer独自技術とかは使っていないので、これができればどんな環境でも大抵動かせると思います。

検証しながら書いているので、間違い・勘違いなどあれば指摘いただけると助かります。

構成とバージョン

  • Kubernetes v0.5.3
  • CentOS Linux release 7.0.1406 (Core)
  • Docker 1.2.0 (extrasリポジトリ)
  • golang 1.3.3 (extrasリポジトリ)
  • etcd v0.4.6
  • flannel v0.1.0

サーバを3台用意します。 それぞれのサーバのサーバ名(ホスト名)、役割、起動するプロセスは以下のとおりです。

  • k8s-master1 : Master + Worker : kube-apiserver, kube-controller-manager, kubelet, kube-proxy, kube-scheduler, docker, etcd, flannel
  • k8s-minion1 : Worker : kubelet, kube-proxy, docker, flannel
  • k8s-minion2 : Worker : kubelet, kube-proxy, docker, flannel

SoftLayerの環境はeth0がLocal Network(Private IP)、eth1がPublic Network(Global IP)になります。 eth0側は10.x.x.xのうちのCIDRが割当られるので、k8sで使うアドレス帯は172.17.0.0/16、flannelで使うアドレス帯は172.18.0.0/16に変更しています。

動作概要

k8sに対するコンテナ作成等もろもろの操作はkube-apiserverに対して実施します。 設定はetcdに保存され、各サーバに伝搬します。

通信のendpointはServiceごとになります。

Serviceへの通信はkube-proxyが仲介しますが、kube-proxyに集約するためにkube-proxyが自サーバのiptablesをガリガリと書き換え、定期的にチェックしています。 コンテナ間通信がホストをまたぐ場合はkube-proxyとkube-proxyでやりとりをしたいところですが、うまくやるためにdockerをeth0にbridgeしたりすると大変なので、flannelを使ってオーバーレイネットワークを作ることで解決しています。

インストール

SoftLayerで仮想マシンを3台起動します。 そしてそれぞれにログインします。 諸事情によりプロビジョニングスクリプトは今回は利用しません。

なおiptablesをかなりガンガン使うので、インストール前の状態として全許可になっていたほうがよいです。 SoftLayerのCentOS7はデフォルトで全許可になっていたので特に問題なかったのですが、 もしiptables(firewalld)が有効なら firewall-cmd --set-default-zone=trusted しておいてください。

まずは全台に対してrootでログインして必要なものをインストールし、master用とminion用のk8s起動用スクリプトを作成します。

厳密にはmasterにはminion用の起動スクリプトは不要だし、minionにはmaster用のetcdや起動スクリプトは不要ですが、たいした量ではないので一括でインストールしてしまいます。


yum -y clean all
yum -y update

yum -y install golang
yum -y install git

yum -y install kernel-headers
git clone https://github.com/coreos/flannel.git /opt/flannel
cd /opt/flannel
git checkout v0.1.0
./build

git clone https://github.com/coreos/etcd.git /opt/etcd
cd /opt/etcd
git checkout v0.4.6
./build

git clone https://github.com/coreos/etcdctl.git /opt/etcdctl
cd /opt/etcdctl
git checkout v0.4.5
./build

yum -y install docker

git clone https://github.com/GoogleCloudPlatform/kubernetes.git /opt/kubernetes
cd /opt/kubernetes
git checkout v0.5.3

cd /opt/kubernetes

sed -e '36,37s/^/#/' -e 's/--machines=".*"/--machines="${MACHINES}"/' -e '111,112s/".*"/"${MYADDRESS}"/' -e '145,146s/^/#/' -e 's@--portal_net=".*"@--portal_net="172.17.0.0/16"@' hack/local-up-cluster.sh > hack/local-up-master.sh
chmod a+x hack/local-up-master.sh

sed -e '36,37s/^/#/' -e '87,105s/^/# /' -e '122,126s/^/# /' -e '130,131s/^/# /' -e '134s/^/# /' -e '143s/^/# /' -e '139,140s/^/# /' -e '111,112s/".*"/"${MYADDRESS}"/' -e '145,146s/^/#/' -e 's/127.0.0.1:4001/${API_HOST:?}:4001/' hack/local-up-cluster.sh > hack/local-up-minion.sh
chmod a+x hack/local-up-minion.sh

ここまではProvisioning Scriptでやってしまってもいいかもしれませんね。

次に起動の準備をします。 以下のように全サーバの /etc/hosts にPrivate IPと、k8s用のホスト名を登録します。 この登録はk8s的には必要ないのですが、私手順で取り扱い易くするために敢えて別のホスト名を設定しています。


echo '10.110.203.195 kube-master1' | tee -a /etc/hosts
echo '10.110.203.194 kube-minion1' | tee -a /etc/hosts
echo '10.110.203.196 kube-minion2' | tee -a /etc/hosts

これで準備は完了です。 まずはk8s-master1でetcd、flannel、docker、k8sを この順番で 起動します。


cd /opt/kubernetes
export MASTER_HOST=kube-master1
export LOCAL_IF=eth0
export API_HOST=$(getent hosts kube-master1 | awk '{print $1}')
export KUBERNETES_PROVIDER=local
export KUBERNETES_MASTER=http://${API_HOST:?}:8080
export MYADDRESS=$(ip a show ${LOCAL_IF:?} | grep -w inet | awk '{print $2}' | cut -d / -f 1)
export MACHINES=$(getent hosts | grep -w "kube" | awk '{print $1}' | xargs echo | sed 's/ /,/g')

/opt/etcd/bin/etcd -name `uname -n` -data-dir /tmp/etcd-data -addr ${MYADDRESS:?}:4001 -peer-addr ${MYADDRESS}:7001 >/tmp/etcd.log 2>&1 &
sleep 3
/opt/etcdctl/bin/etcdctl mk /coreos.com/network/config '{"Network":"172.18.0.0/16"}'

/opt/flannel/bin/flanneld -ip-masq=true -etcd-endpoint=http://${API_HOST:?}:4001 >/tmp/flanneld.log 2>&1 &
sleep 3
source /run/flannel/subnet.env
sleep 1

/usr/bin/docker -d --selinux-enabled --bip=${FLANNEL_SUBNET:?} --mtu=${FLANNEL_MTU:?} --host=unix:///var/run/docker.sock >/tmp/docker.log 2>&1 &

hack/local-up-master.sh

随所に配置された sleep が涙ぐましいですね。 うまくいかない場合は /tmp 配下にログが色々出ているので確認してみてください。

次にk8s-minion1とk8s-minion2でもflannel、docker、k8sをこの順番で起動します。


cd /opt/kubernetes
export MASTER_HOST=kube-master1
export LOCAL_IF=eth0
export API_HOST=$(getent hosts kube-master1 | awk '{print $1}')
export KUBERNETES_PROVIDER=local
export KUBERNETES_MASTER=http://${API_HOST:?}:8080
export MYADDRESS=$(ip a show ${LOCAL_IF:?} | grep -w inet | awk '{print $2}' | cut -d / -f 1)
export MACHINES=$(getent hosts | grep -w "kube" | awk '{print $1}' | xargs echo | sed 's/ /,/g')

/opt/flannel/bin/flanneld -ip-masq=true -etcd-endpoint=http://${API_HOST:?}:4001 >/tmp/flanneld.log 2>&1 &
sleep 3
source /run/flannel/subnet.env
sleep 1

/usr/bin/docker -d --selinux-enabled --bip=${FLANNEL_SUBNET:?} --mtu=${FLANNEL_MTU:?} --host=unix:///var/run/docker.sock >/tmp/docker.log 2>&1 &

hack/local-up-minion.sh

ここまでくれば設定は完了です。 minion が3つ(k8s-master, k8s-minion1, k8s-minion2)登録できていれば成功です。 /minions の代わりに /pods , /services , /replicationControllers も指定可能です。 よく使うので覚えておきましょう。


[root@k8s-master1 kubernetes]# cluster/kubecfg.sh list /minions
Minion identifier
----------
10.110.203.194
10.110.203.196
10.110.203.195

v0.5.0からはkubecfgではなくkubectlを使うらしいのですが、ここではguestbookの例に従ってkubecfgを使っています

※kubecfgの出力はデフォルトではソートされないため、実行するたびに順番が変わるので注意してください

guestbook exampleを動かす

k8sには例がいくつか同梱されているので、その中でもお手軽なguestbookを動かしてみます。


cd /opt/kubernetes
export MASTER_HOST=kube-master1
export LOCAL_IF=eth0
export API_HOST=$(getent hosts kube-master1 | awk '{print $1}')
export KUBERNETES_PROVIDER=local
export KUBERNETES_MASTER=http://${API_HOST:?}:8080
export MYADDRESS=$(ip a show ${LOCAL_IF:?} | grep -w inet | awk '{print $2}' | cut -d / -f 1)
export MACHINES=$(getent hosts | grep -w "kube" | awk '{print $1}' | xargs echo | sed 's/ /,/g')

cluster/kubecfg.sh -c examples/guestbook/redis-master.json create pods
# ※しばし待つ1
cluster/kubecfg.sh -c examples/guestbook/redis-master-service.json create services
cluster/kubecfg.sh -c examples/guestbook/redis-slave-controller.json create replicationControllers
# ※しばし待つ2
cluster/kubecfg.sh -c examples/guestbook/redis-slave-service.json create services
cluster/kubecfg.sh -c examples/guestbook/frontend-controller.json create replicationControllers
# ※しばし待つ3

※しばし待つ1〜3 のところで必要なdocker imageのをpullするため、かなり時間がかかります。 裏で非同期実行してくれるのでコンソール操作が止まることはないのですが、最初は pods のステータスを見て PendingRunning になってから次に進むのが無難かなと思います。

cluster/kubecfg.sh -c examples/guestbook/frontend-service.json create services は不要でした。@2014.12.2訂正


cluster/kubecfg.sh list /pods

最終的に全て Running になれば成功です。


[root@k8s-master1 kubernetes]# cluster/kubecfg.sh list /pods
Name                                   Image(s)                   Host                Labels                                       Status
----------                             ----------                 ----------          ----------                                   ----------
63d5bfdf-7561-11e4-a0d4-0626f523798c   brendanburns/php-redis     10.110.203.195/     name=frontend,uses=redisslave,redis-master   Running
redis-master                           dockerfile/redis           10.110.203.194/     name=redis-master                            Running
314f5cec-7519-11e4-959f-0626f523798c   brendanburns/redis-slave   10.110.203.196/     name=redisslave,uses=redis-master            Running
314f9a36-7519-11e4-959f-0626f523798c   brendanburns/redis-slave   10.110.203.195/     name=redisslave,uses=redis-master            Running
631decf1-7519-11e4-959f-0626f523798c   brendanburns/php-redis     10.110.203.194/     name=frontend,uses=redisslave,redis-master   Running
63200b5b-7519-11e4-959f-0626f523798c   brendanburns/php-redis     10.110.203.196/     name=frontend,uses=redisslave,redis-master   Running

この状態でChromeで http://(Public IP):8000/ アクセスするとguestbookが表示されます。 Public IPはホストOSのeth1にアサインされているグローバルIPアドレスです。

Guestbook.png

なお、このguestbookは結構バギーで、同じ値を複数回投稿すると壊れたりします。 あまり細かいことは気にしないようにしましょう。

まとめ

SoftLayer+k8sはいかがだったでしょうか? dockerまわりなどpullでかなり帯域を食うので、このような検証でもぜひクラウドをご活用ください。

ではでは。

株式会社ハートビーツの技術情報やイベント情報などをお届けする公式ブログです。