Kubernetes 1.13とFlannelでubuntu 18.04上にpod間overlayネットワークを構成～Master Node構築編～

本記事は[「クラウド時代のシステム管理」の記事](https://www.takanyan.net/k8s1-13-flannel-overlay-01/)の転載です。

Kubernetesは3ヶ月ごとに新バージョンがリリースされ、機能がどんどん変化して行きます。本記事では、<a href="https://www.takanyan.net/interact2018_flannel/" rel="noopener" target="_blank">2018年6月に私が登壇して話したFlannelを使ったpod間ネットワークの自動構成</a>を最新のバージョンで実現しようとした記録です。

<!--more-->

## 1. 構築する環境構成

### 1-1. 構成要素とバージョン

本記事で利用するソフトウェアのバージョンは以下の通りです。

|ソフトウェア名|バージョン|
|:--:|:--:|
|Master NodeのOS|ubuntu server 18.04.1|
|Linux Worker NodeのOS|ubuntu server 18.04.1|
|Windows Worker NodeのOS|Windows Server 2019 Datacenter(デスクトップ有効)|
|Kubernetes|1.13.2|
|flannel|v0.10.0|

過去の記事ではWinCNI、flannel、calicoなどいくつかのツールを使ってWindows Worker Node上のPod間ネットワークを構成してきましたが、いずれも各NodeでNATを行うホストGatewayモード、L2Bridgeモードを用いてきており、Overlayネットワークを使うのは今回が初めてとなります。

### 1-2. 参考資料とハマりポイントのまとめ

今回の記事作成に当たり、参考としたサイトは以下の通りです。

* <a href="https://github.com/Microsoft/SDN/tree/master/Kubernetes/flannel/overlay" rel="noopener" target="_blank">Github上のmicrosoft/SDNレポジトリ</a>
* <a href="https://kubernetes.io/docs/setup/" rel="noopener" target="_blank">Setup Kubernetes</a>
* <a href="https://github.com/coreos/flannel/commits/master/Documentation/kube-flannel.yml" rel="noopener" target="_blank">Github上のflannelリポジトリ中のconfig.yamlファイル</a>
* <a href="https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/" rel="noopener" target="_blank">Customizing DNS Service</a>


基本的には一つ目にあるMicrosoft/SDNリポジトリ内のREADMEを参考にしていますが、以下のようないくつかハマりポイントと古い設定情報がありました。

1. Kubernetes 1.13がubuntu 18.04のMaster Nodeでうまく起動できなかった。これはdockerをaptではなくsnapからインストールしていたためでした。厳密にはOSインストール時にdockerを有効にするようにしていたためでした。
2.  FlannelがMasterおよびLinux Workerで正常に起動しなかった。Kubernetes 1.12以降ではMicrosoft/SDNリポジトリ内にある<a href="https://github.com/Microsoft/SDN/blob/master/Kubernetes/flannel/overlay/kube-flannel-vxlan.yaml" rel="noopener" target="_blank">kube-flannel-vxlan.yaml</a>を一部修正する必要があり、3つ目の参考リンクをみて対応しました。
3.  Flannel起動後、coreDNSが正しく名前解決できず、プライベートIPの逆引きも8.8.8.8へ問い合わせし続けていた。Kubernetesでは名前解決の情報をMaster Nodeの/etc/resolv.confから取得するのですが、ubuntu 18.04では中身が127.0.0.53というsystemdでコントロールするloopbackアドレスのみが書かれているため、正しいリゾルバIPが取得できません。そこで4つ目の参考リンクをみてリゾルバIPを指定して対処しました。
4. Windows Worker Nodeでkubeletを起動しようとしましたが、flanneld.exeによるVXLAN overlayネットワークの作成で例外エラーが出てしまいます。flanneld.exeはMicrosoft/SDNリポジトリ内にあるものを使っているので、コードの修正をして自分でビルドする必要があるかなと思っています。(対応未完了)

これだけ色々ハマったので、今回はubuntu 18.04.1上にKubernetes 1.13のMaster Nodeを構築する手順までを紹介します。

## 2. Master Nodeの構成

### 2-1. 前提条件ソフトウェアのインストール

最初にubuntu Server 18.04.1をインストールします。OSインストールの途中で追加するパッケージを選ぶことが可能ですが、ここでは何も追加せずデフォルト状態のままインストールを完了させます。

OS起動後、OS自体のパッチを適用します。

```
$ sudo apt-get update
$ sudo apt-get upgrade
```

次にdockerをインストールします。

```
$sudo apt-get install docker.io
```

パッケージのインストールを実施後、Kubernetes導入の前提条件であるスワップ無効化を行います。

```
$ sudo swapoff
$ sudo vi /etc/fstab
(swap.imgに関する設定行をコメントアウトします)
```

以上の設定を実施後、いったんOS再起動を行います。

### 2-2. Kubernetes 1.13のセットアップ

まずは<a href="https://kubernetes.io/docs/setup/independent/install-kubeadm/" rel="noopener" target="_blank">公式ドキュメントの"Installing kubeadm"</a>に従ってkubeadm, kubelet, kubectlをインストールします。

```
$ sudo -i
# apt-get install -y apt-transport-https curl
# 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 https://apt.kubernetes.io/ kubernetes-xenial main
EOF
# apt-get update
# apt-get install -y kubelet kubeadm kubectl
# apt-mark hold kubelet kubeadm kubectl
```

次に、<a href="https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/" rel="noopener" target="_blank">Kubernetesドキュメントの"Creating a single master cluster with kubeadm"</a>に従って、kubeadmによるKubernetes Master Nodeのセットアップを行います。kubeadmコマンドの引数には、FlannelでPod間通信用に使われるPod Network CIDRとして"10.244.0.0/16"を利用するよう引数に指定します。

```
# kubeadm init --pod-network-cidr=10.244.0.0/16
（中略）

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

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the addon options listed at:
  http://kubernetes.io/docs/admin/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
```

次に、kubectlコマンドを実行できるよう、一般ユーザーにて以下のコマンドを実行します。


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

kubectlが使えることとKubernetes Master NodeとしてのPodが動いていることを確認します。

```
$ kubectl get pods -o wide --all-namespaces
NAMESPACE     NAME                                          READY   STATUS    RESTARTS   AGE    IP             NODE                   NOMINATED NODE   READINESS GATES
kube-system   coredns-86c58d9df4-6cwhg                      0/1     Pending   0          161m   <none>         <none>                 <none>           <none>
kube-system   coredns-86c58d9df4-9ss9n                      0/1     Pending   0          161m   <none>         <none>                 <none>           <none>
kube-system   etcd-<Master Nodeのホスト名>                   1/1     Running   0          160m   192.168.1.40   <Master Nodeのホスト名> <none>           <none>
kube-system   kube-apiserver-<Master Nodeのホスト名>         1/1     Running   0          160m   192.168.1.40   <Master Nodeのホスト名> <none>           <none>
kube-system   kube-controller-manager-<Master Nodeのホスト名>1/1     Running   0          160m   192.168.1.40   <Master Nodeのホスト名> <none>           <none>
kube-system   kube-proxy-lbbdw                              1/1     Running   0          161m   192.168.1.40   <Master Nodeのホスト名> <none>           <none>
kube-system   kube-scheduler-<Master Nodeのホスト名>         1/1     Running   0          160m   192.168.1.40   <Master Nodeのホスト名> <none>           <none>
```

### 2-3. coreDNSの設定

ここまでのセットアップ結果を見るとまだcorednsのPodが起動しておらずPending状態となっています。これはpod間ネットワークの構成が完了するまでcorednsは起動しないという既定の動作です。ただ、corednsは/etc/resolv.conにある<strong>127.x.x.xではない</strong>DNSリゾルバのIPを取得して名前解決リクエストの転送先として使います。さらに、/etc/resolv.confに該当するIPが一つも存在しない場合は、「8.8.8.8」と「8.8.4.4」の2つが利用されます。
これではプライベートな名前空間の名前解決ができないため、実際の環境に合わせたリゾルバを設定します。

まず、以下の内容でcoredns.yamlファイルを作成します。

```
apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           upstream  【DNSリゾルバIP。複数ある場合はスペース区切り】
           fallthrough in-addr.arpa ip6.arpa
        }
        prometheus :9153
        proxy . 【DNSリゾルバIP。複数ある場合はスペース区切り】
        cache 30
        loop
        reload
        loadbalance
    }
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
```

次に上記ファイルを使ってKubernetesの設定変更を行います。

```
$ kubectl apply -f coredns.yaml
```

これでcorednsからの参照先DNSが正しく設定できました。


### 2-4. Flannelの導入

最初にCNIの最新リリースバージョンをダウンロードして展開します

```
$ sudo mkdir -p /opt/cni/bin
$ cd sudo /opt/cni/bin
$ https://github.com/containernetworking/plugins/releases/download/v0.7.4/cni-plugins-amd64-v0.7.4.tgz
$ sudo tar zxf cni-plugins-amd64-v0.7.4.tgz
```

VXLAN Overlayネットワークを構成するためのFlannel導入設定ファイルをMicrosoft/SDNリポジトリからダウンロードします。

```
$ wget https://raw.githubusercontent.com/Microsoft/SDN/master/Kubernetes/flannel/overlay/kube-flannel-vxlan.yaml
```

次に、Kubernetes 1.13で正常にFlannelのDaemonSetが起動するよう、一部修正を行います。

```
$ vi kube-flannel-vxlan.yaml
(DaemonSet > Spec > Template > Specの下を編集）
      tolerations:
-      - key: node-role.kubernetes.io/master
-        operator: Exists
+      - operator: Exists
```

また、Linux OSのみにDaemonSetを起動するよう設定を編集します。

```
    spec:
      nodeSelector:
        beta.kubernetes.io/arch: amd64
+        beta.kubernetes.io/os: linux         ←この行を追記
```

次に編集したYAMLファイルを適用してFlannelを導入します。

```
$ kubectl apply -f kube-flannel-vxlan.yaml
```

適用が完了するとMaster Node上のPodはすべてRunning状態となり、「flannel.4096」と「cni0」というNICが追加されます。

```
# kubectl get pods -o wide --all-namespaces
NAMESPACE     NAME                                          READY   STATUS              RESTARTS   AGE     IP             NODE                  NOMINATED NODE   READINESS GATES
kube-system   coredns-86c58d9df4-4gs5s                      1/1     Running             0          3d      10.244.0.3     kube-flannel-master   <none>           <none>
kube-system   etcd-kube-flannel-master                      1/1     Running             1          3d      192.168.1.40   kube-flannel-master   <none>           <none>
kube-system   kube-apiserver-kube-flannel-master            1/1     Running             1          3d      192.168.1.40   kube-flannel-master   <none>           <none>
kube-system   kube-controller-manager-kube-flannel-master   1/1     Running             2          3d      192.168.1.40   kube-flannel-master   <none>           <none>
kube-system   kube-flannel-ds-rbhgj                         1/1     Running             1          3d      192.168.1.40   kube-flannel-master   <none>           <none>
kube-system   kube-proxy-qw8nk                              0/1     ContainerCreating   0          2d10h   192.168.1.51   winworker11           <none>           <none>
kube-system   kube-proxy-sqb7k                              1/1     Running             1          3d      192.168.1.40   kube-flannel-master   <none>           <none>
kube-system   kube-scheduler-kube-flannel-master            1/1     Running             2          3d      192.168.1.40   kube-flannel-master   <none>           <none>
```

以上でMaster Nodeの構築までが完了しました。