kubernetes
flannel
kubeadm

kubeadm で kubernetes v1.8 + Flannel をインストール

kubeadm について

kubeadm は kubernetes をデプロイするためのツール。公式ドキュメントでも紹介されているツールで、まだベーダ版だが kubernetes クラスタを構築する際には今後はこのツールを使っていくことになる。他には Minikube というツールもあるが、こちらはローカルで kubernetes を構築するためのもので、主に開発者に使われることを想定している。

環境

自分の試した環境は以下のとおり。

  • ホストOS: MacOS Sierra
  • ゲストOS: Ubuntu 16.04.2 LTS
  • VirtualBox 5.1.14
  • Vagrant 1.9.1

用意した VM は3つ。マスターノード用に 2vCPU, 4GB の VM が1つ、ワーカーノード用に 1vCPU, 2GB の VM が2つ、それぞれのホスト名は manager, host1, host2 とする。各 VM のデフォルトの NIC はホストへの NAT になっていて、インターネットへのアクセスに使用する。これとは別に private_network を用意し、それぞれの IP アドレスを下記の通り 192.168.33.10, 192.168.33.11, 192.168.33.12 とする。Kubernetes のすべての通信はこの NIC を使用する。

       +---------------------------------------------+
       |                     NAT                     |
       +--+-------------------+-------------------+--+
          |                   |                   |
+---------+-------+  +--------+--------+  +-------+---------+
| enp0s3 10.0.2.15|  | enp0s3 10.0.2.15|  | enp0s3 10.0.2.15|
|                 |  |                 |  |                 |
|                 |  |                 |  |                 |
|                 |  |                 |  |                 |
|     manager     |  |     host1       |  |     host2       |
|                 |  |                 |  |                 |
|                 |  |                 |  |                 |
| enp0s8          |  | enp0s8          |  | enp0s8          |
| 192.168.33.10   |  | 192.168.33.11   |  | 192.168.33.12   |
+---------+-------+  +--------+--------+  +-------+---------+
          |                   |                   |
       +--+-------------------+-------------------+--+
       |               192.168.33.0/24               |
       +---------------------------------------------+


kubeadm インストール

この章で実施している内容をマスター、ワーカーの各ノードで実行する。基本的には公式ドキュメントの最新情報を確認して欲しいが、いくつか補完する。

/etc/hosts ファイルの編集

各ノードの /etc/hosts に下記の通り、ホスト名に対応する IP アドレスを追記する。このときループバックアドレス以外の別の IP アドレス (e.g. 10.0.2.15) とホスト名を紐付ける記述はしてはいけない。

manager ノード

/etc/hosts
192.168.33.10 manager

host1 ノード

/etc/hosts
192.168.33.11 host1

host2 ノード

/etc/hosts
192.168.33.12 host2

Docker インストール

Ubuntu 公式リポジトリの docker を使うのが手間がなくて良いが、出来るだけ新しいものを使いたいので自分は docker リポジトリのものを使った。公式ドキュメントでは17.09を指定しているが、kubeadm が公式にサポートしているのは17.03で、kubeadm 実行時に warning も出るので自分は17.03を使った。

Ubuntu リポジトリの Docker を使う場合

$ apt-get update
$ apt-get install -y docker.io

Docker リポジトリの Docker を使う場合

$ apt-get update
$ apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
$ add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
   $(lsb_release -cs) \
   stable"
$ apt-get update && apt-get install -y docker-ce=17.03.0~ce-0~ubuntu-xenial

kubeadm, kubectl, kubelet インストール

$ apt-get update && apt-get install -y apt-transport-https
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
$ cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ apt-get update
$ apt-get install -y kubelet kubeadm kubectl

kubeadm 実行

今回マスターノードが使用する IP アドレスは 192.168.33.10 で、このアドレスを指定するには --apiserver-advertise-address を使用する。またマニュアルには flannel 使用時には --pod-network-cidr を指定するようにと記載があるため、そのように指定する。

$ sudo kubeadm init --apiserver-advertise-address=192.168.33.10 --pod-network-cidr=10.244.0.0/16

デプロイ後に表示される kubeadm join コマンドはメモしておくこと。後で、このコマンドと引数を使ってワーカーノードをクラスタに追加します。

kubeadm join --token 07953d.ad9fc560f05ae297 192.168.33.10:6443 --discovery-token-ca-cert-hash sha256:23b6e03c9d4c3cd752c29f3fb0bb0f04923dd69e39020d995b976f93607316e1

kube config ファイルをコピーする。

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

これで基本的なプロセスのデプロイは完了。 kubectl コマンドでノードの状態や pod の情報を取得してみる。

$ kubectl get nodes
NAME      STATUS     ROLES     AGE       VERSION
manager   NotReady   master    18m       v1.8.4

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                              READY     STATUS    RESTARTS   AGE       IP              NODE
kube-system   etcd-manager                      1/1       Running   0          18m       192.168.33.10   manager
kube-system   kube-apiserver-manager            1/1       Running   0          18m       192.168.33.10   manager
kube-system   kube-controller-manager-manager   1/1       Running   0          18m       192.168.33.10   manager
kube-system   kube-dns-545bc4bfd4-pc5qh         0/3       Pending   0          19m       <none>          <none>
kube-system   kube-proxy-8fzzd                  1/1       Running   0          19m       192.168.33.10   manager
kube-system   kube-scheduler-manager            1/1       Running   0          18m       192.168.33.10   manager

マスターノードのステータスはまだ NotReady です。これは kube-dns がまだ動いていない、NW が未設定であるためです。

flannel のデプロイ

通常は下記のコマンドを実行すれば終わりですが、問題2 でも取り上げている内容の通り kube-flannel.yml の修正が必要になります。

$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml

kube-flannel.yml をダウンロードし、flanneld の起動オプションに NIC 指定を追記します。

kube-flannel.yaml
command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr", "--iface=enp0s8"]

編集し終わったら kubectl apply で NW 設定を適用します。

$ kubectl apply -f kube-flannel.yml

これでノードのステータスは Ready になります。

$ kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
manager   Ready     master    35m       v1.8.4

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                              READY     STATUS    RESTARTS   AGE       IP              NODE
kube-system   etcd-manager                      1/1       Running   0          34m       192.168.33.10   manager
kube-system   kube-apiserver-manager            1/1       Running   0          34m       192.168.33.10   manager
kube-system   kube-controller-manager-manager   1/1       Running   0          33m       192.168.33.10   manager
kube-system   kube-dns-545bc4bfd4-pc5qh         3/3       Running   0          34m       10.244.0.8      manager
kube-system   kube-flannel-ds-tggqx             1/1       Running   0          1m        192.168.33.10   manager
kube-system   kube-proxy-8fzzd                  1/1       Running   0          34m       192.168.33.10   manager
kube-system   kube-scheduler-manager            1/1       Running   0          34m       192.168.33.10   manager

ワーカーノードをクラスタに追加

マスターノードの準備が終わったので、あとは各ノードでメモしておいた join コマンドをそのまま実行していくだけです。

$ sudo kubeadm join --token 07953d.ad9fc560f05ae297 192.168.33.10:6443 --discovery-token-ca-cert-hash sha256:23b6e03c9d4c3cd752c29f3fb0bb0f04923dd69e39020d995b976f93607316e1

完了。

$ kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
host1     Ready     <none>    13m       v1.8.4
host2     Ready     <none>    13s       v1.8.4
manager   Ready     master    52m       v1.8.4

問題

今回の構築でいくつか問題にハマったので共有します。

問題1

各 pod の IP アドレスが各ノードのデフォルトインターフェースのアドレスになっている。下記を見てわかる通り manager も host1 もホストに対して NAT をしている NIC がデフォルトのため同じ IP アドレス (10.0.2.15) になってしまっている。この状態だとマスターノードから各ノード上の pod のログが取れないなど色々と支障が出る。

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                              READY     STATUS    RESTARTS   AGE       IP           NODE
kube-system   etcd-manager                      1/1       Running   0          5m        10.0.2.15    manager
kube-system   kube-apiserver-manager            1/1       Running   0          5m        10.0.2.15    manager
kube-system   kube-controller-manager-manager   1/1       Running   0          5m        10.0.2.15    manager
kube-system   kube-dns-545bc4bfd4-m2cm4         3/3       Running   0          6m        10.244.0.6   manager
kube-system   kube-flannel-ds-cljpz             1/1       Running   0          2m        10.0.2.15    manager
kube-system   kube-flannel-ds-p9lfd             1/1       Running   0          10s       10.0.2.15    host1
kube-system   kube-proxy-cphtp                  1/1       Running   0          6m        10.0.2.15    manager
kube-system   kube-proxy-hs6b2                  1/1       Running   0          10s       10.0.2.15    host1
kube-system   kube-scheduler-manager            1/1       Running   0          5m        10.0.2.15    manager

この解決策の1つとして kubelet を起動する際に --node-ip というオプションで任意の IP アドレスを渡すことができるが、kubeadm では対応してない。指定されていない場合は /etc/hosts に設定されているホスト名の IP アドレスが使用されるため、あらかじめ各ノードで kubernetes 用に使用する IP アドレスを /etc/hosts に登録する必要がある。

/etc/hosts
kubernetesで使用するIPアドレス ホスト名

問題2

Flannel が VXLAN トンネルを張る際にデフォルトの NIC を使う。マシン同士が疎通可能ならそれでも問題はないが、今回のような環境 (NAT) だと VXLAN が張れないので flanneld 起動時に使用する NIC を指定する必要がある。今回は下記のように flannel を適用する際に使用した kube-flannel.yaml を直接編集した。

kube-flannel.yaml
command: [ "/opt/bin/flanneld", "--ip-masq", "--kube-subnet-mgr", "--iface=xxx" ]

問題3

任意の pod が起動してるノードから、その pod への通信は通るが、別のノードからその pod への通信が通らない。これは Docker v1.13 以降と Flannel の組み合わせのバグで、自分がハマっていたときには未修正だったが、修正はすでにされている。kube-flannel.ymlもこの修正が入ったイメージ (v0.9.1-amd64) が指定されているので、今からやる人は特にハマらないはず。しかし、自分がハマった時は、tcpdump祭りで見つけられず、泣きながら iptables のルールを読んで、flannel のソースコード読んで原因を突き止めたので、v0.9.0 でハマって諦めた人用にメモとして残しておく。