Kubernetesクラスターを「クラウド↔自宅ネットワーク」間で作る（後編）

## 概要

KubernetesのMasterノードをクラウド上に作り、Workerノードを自宅LAN内にあるLinuxマシンに構築できたので、その方法を紹介。
[前回の記事](https://qiita.com/showchan33/items/4c9030ee5ac2ae8a24e8)でMasterとWorkerの２ノードを作成して、各ノードのPodに`kubectl exec`コマンドでアクセスできることは確認できたが、Pod間で通信を行うためのCNI(Container Network Interface)の設定は未完了であった。
そこで今回、Pod間のネットワークをつなぐツールの一つであるCalicoを使って前回のやり残し部分を完成させる。

## 実現したい構成

下図のように、予め定義したIPアドレス範囲（図の例では``10.128.0.0/16``）でPod間通信できるようにする。ちなみにk8sクラスターをkubeadmで構築する場合、Podで利用するアドレス範囲は``kubeadm init``コマンドの引数``--pod-network-cidr``で指定が必要。

![network-cni2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370519/9ec00d07-083c-7412-6c15-d56d2d1e8ab1.png)

[前回記事](https://qiita.com/showchan33/items/4c9030ee5ac2ae8a24e8)の手順で、既に２つのノードをクラスターに追加済。

```
$ kubectl get node -o wide
NAME         STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE ...
k8s-master   Ready    master   8d    v1.18.8   20.30.40.50   <none>        Ubuntu 18.04.3 LTS             ...
k8s-worker   Ready    <none>   23h   v1.18.8   192.168.1.4   <none>        Debian GNU/Linux 9 (stretch)   ...
```

k8s-workerマシンのIP`192.168.1.4`は自宅LAN内のプライベートIPになってしまっているので、自宅外のネットワークから`kubectl exec`等でWorkerノードのPodにアクセスする場合は、`192.168.1.4`を`60.70.80.90`にNATする設定が必要。何でプライベートIPになってしまうのかは、[前回記事](https://qiita.com/showchan33/items/4c9030ee5ac2ae8a24e8#2-kubelet%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E8%B5%B7%E5%8B%95%E6%99%82%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89ip%E6%8C%87%E5%AE%9A)を参照いただきたい。
（今回Calicoを使ってPod間ネットワークを構築する場合も、WorkerノードのIPがデフォルトではプライベートIPとして認識されてしまい、対処が必要となる。）

## Calicoのデプロイ

### (1) 開放が必要なポート

以下サイトに記載があるが、
https://docs.projectcalico.org/getting-started/kubernetes/requirements

CalicoのデフォルトではBGP(Border Gateway Protocol)を使ってノードをまだいだPod間通信を実現するようなので、各ノードで**ポート番号179(TCP)のインバウンド方向の通信を許可する必要あり**。自宅LAN側は[前回記事](https://qiita.com/showchan33/items/4c9030ee5ac2ae8a24e8#1-%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E8%A8%AD%E5%AE%9A%E3%83%9D%E3%83%BC%E3%83%88%E8%A7%A3%E6%94%BE)と同様に、ルーターのポート開放、およびWorkerノードへのポート転送設定が必要。

### (2) マニフェストのダウンロードと設定

ポートが開放できたら、Calicoのマニフェストをダウンロード。

```
$ wget https://docs.projectcalico.org/manifests/calico.yaml
```
ダウンロードしたcalico.yamlで、下記の行(3674行目あたり)の#を外して、value:に予め定めたPodのアドレス範囲(本例では``10.128.0.0./16``)を記入。

```yaml:calico.yaml
             (省略)
             # - name: CALICO_IPV4POOL_CIDR
             #   value: "192.168.0.0/16" # -> "10.128.0.0./16"に変更
             (省略)
```

Calicoのリソースを下記コマンドで作成。

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

普通のクラスター構成だったらこれだけやればあっさりとPod間通信できるようになるのだが、今回はネットワーク構成が特殊なために上手く行かない。以下のように、calico-nodeのPodがReadyになってくれない…。

```
$ kubectl get pod -n kube-system -o wide
NAME                                       READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
calico-kube-controllers-8586758878-jzdlw   1/1     Running   0          104s    10.128.75.0    k8s-worker   <none>           <none>
calico-node-79zbk                          0/1     Running   0          105s    20.30.40.50    k8s-master   <none>           <none>
calico-node-n5nqf                          0/1     Running   0          105s    192.168.1.4    k8s-worker   <none>           <none>
coredns-66bff467f8-djn4w                   1/1     Running   0          9d      10.128.117.2   k8s-master   <none>           <none>
coredns-66bff467f8-gf842                   1/1     Running   0          9d      10.128.117.3   k8s-master   <none>           <none>
etcd-k8s-master                            1/1     Running   0          9d      20.30.40.50    k8s-master   <none>           <none>
kube-apiserver-k8s-master                  1/1     Running   0          9d      20.30.40.50    k8s-master   <none>           <none>
kube-controller-manager-k8s-master         1/1     Running   5          9d      20.30.40.50    k8s-master   <none>           <none>
kube-proxy-p6bwq                           1/1     Running   1          2d      192.168.1.4    k8s-worker   <none>           <none>
kube-proxy-xdtzc                           1/1     Running   0          9d      20.30.40.50    k8s-master   <none>           <none>
kube-scheduler-k8s-master                  1/1     Running   5          9d      20.30.40.50    k8s-master   <none>           <none>
```

calico-nodeがReadyとならない原因を先に言ってしまうと、**Pod間通信を実現するための各ノードのBGPピアのIPアドレスがプライベートIPになっている**ためである。２つのノードはインターネット経由で通信する必要があり、BGPピアのIPアドレスは公開IPにする必要がある。
今回はCalicoの設定確認や変更が可能な「calicoctl」を使ってこの問題を解決する。

## calicoctlのインストール＆BGPピアIP設定

まずは、以下サイトのcalicoctlをインストールする。

https://docs.projectcalico.org/getting-started/clis/calicoctl/install

現時点の最新バージョンはv3.17.1で、以下の手順でcalicoctlを使えるようにする。

```
$ curl -O -L  https://github.com/projectcalico/calicoctl/releases/download/v3.17.1/calicoctl
$ sudo mv calicoctl /usr/local/bin/
$ sudo chown root:root calicoctl
$ sudo chmod a+x calicoctl
```

設定後、次のようにしてBGPピアのIPアドレスを確認すると、２つのノードともプライベートIPになっていることがわかる。

```
$ calicoctl get node -o wide
NAME         ASN       IPV4              IPV6   
k8s-master   (64512)   10.0.0.4/24
k8s-worker   (64512)   192.168.1.4/24          
```

BGPピアのIPの変更は、`calicoctl patch`コマンドで`spec.bgp.ipv4Address`を変更することで実現可能。

```
$ calicoctl patch node k8s-master -p '{"spec": {"bgp": {"ipv4Address": "20.30.40.50/24"}}}'
$ calicoctl patch node k8s-master -p '{"spec": {"bgp": {"ipv4Address": "60.70.80.90/24"}}}'
```

しばらく(30秒〜1分程度)待ってCalicoのPodの状態を確認すると、無事にReadyになっている。

```
$ kubectl get pod -n kube-system -o wide | grep ^calico
calico-kube-controllers-8586758878-jzdlw   1/1     Running   0          33m    10.128.75.0    k8s-worker   <none>           <none>
calico-node-79zbk                          1/1     Running   0          33m    20.30.40.50    k8s-master   <none>           <none>
calico-node-n5nqf                          1/1     Running   0          33m    192.168.1.4    k8s-worker   <none>           <none>
```

## おわりに

ネットワーク部分を手動で色々と設定してようやく、クラウドサーバーと自宅のマシンでk8sクラスターを構築できたのだが、こんな七面倒臭いことをやらなくてもスマートにつなげられる方法はきっとあるのだと思う。例えばk8sクラスターを作る前に、予めクラウドサーバーと自宅のマシンで「擬似的なプライベートネットワーク」を作り、そのプライベートネットワーク内でMasterノード、Workerノードを追加していけばすんなり作れるはず。
自分自身、BGPあたりの知識が浅いので（名前は知っていたが、今回構築してみて初めて機能の一部を知ることができた）、その辺を勉強していけばもう少し可能性は見えてくるのかも。