kubernetes the hard way on PC (１３．Pod Network)

#初めに
「[kubernetes the hard way](https://github.com/kelseyhightower/kubernetes-the-hard-way) を PC でやってみる」の１３回目、「Pod Network」についてです。（ [目次](https://qiita.com/shimauma_Zzzzz/items/84ecf5c748ceafd05380#%E8%AA%AC%E6%98%8E%E8%A8%98%E4%BA%8B%E7%9B%AE%E6%AC%A1) ）

各ノード上で稼働する Pod は、各ノードの POD CIDR から IP アドレスが割り振られていきます。
それらの間での通信ができるように　CNI (に相当するもの）を構成します。
一般的には kubernetes のネットワークを構成する場合、 
flannel や calico などで提供される CNI プラグインを利用しますが
kubernetes the hard way ではその代わりにルーティング設定で代替しています。
そのため、kubernetes the hard way で構築したクラスターでは、CNI が持つ Network Policy については利用できません。

この回は非常にハマりました、一見うまくいっているように見えて疎通はできない、という事象になり
さんざん調べてようやく解決した時に振り返って考えると、いかに自分が NW 構成を理解していないかを痛感しました。
ハマった内容については例によって末尾に記載します。。。　まぁまだ間違っているかもしれませんが…

やることは以下の通りです。　**今回は ワーカーノードで実施しています**

- ルーティングの追加

なんとこれだけですね。なのに私は全くうまくいかなかったという。。。


# ルーティングの追加

kubernetes the hard way では、 google cloud のコマンドを使ってルーティングを追加しているようですが、
私には全くわかりませんでした。。。

オンプレ ubuntu でルーティングを追加する場合、（いろいろやり方はあるのでしょうが)
netplan を使って追加するという手段があるようです。 NetworkManager 派なので知りませんでした。

さて、肝心の追加内容は以下の通りです。　（図の赤矢印は k8sworker0 について記載しており、
k8sworker1,2 もそれぞれ自分の POD_CIDR 以外は他のノードにルーティングするように設定します。)
※ 細かく追えるように、IP アドレスも記入していますが、 要は赤い矢印についてだな、ぐらいの認識で OK です）

![50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310495/49731aea-d4d2-abb1-a7ed-37f578ca9434.png)


##ルーティング設定内容

表のデータ部1行目を例にとって説明すると、
k8sworker0 ( 192.168.199.210 ) が持っている POD_CIDR (10.200.0.0/24) への外部からの通信は、
k8sworker0 の IP にルーティングを行うように、 k8sworker1,2 に登録する、ということです。
逆の見方をすると、　自ノードが持つ POD_CIDR 向けは IPtables が転送してくれるのでルーティングテーブルとして登録しない、とも言えます。
（※ 自ノードの POD_CIDR 向けは POD 作成時に cnio0 向けとして自動的に作成されるようです)

|ターゲットNW|ルーティング先|k8sworker0|k8sworker1|k8sworker2|図|
|:--|:--|:--|:--|:--|:--|
|10.200.0.0/24|192.168.199.210||〇|〇||
|10.200.1.0/24|192.168.199.211|〇||〇|①|
|10.200.2.0/24|192.168.199.212|〇|〇||②|


##ルーティング設定方法

netplan でのルーティング設定方法は
/etc/netplan/*.conf を修正して、 `netplan apply` を実行します。
(以下は k8sworker0 の例で、 `routes:` 部分を追記しています。 
k8sworker0 に不要な部分はコメントアウトしています。
k8sworker1,2 ではコメントアウトする部分が変わってきます)

```shell-session
# cd /etc/netplan/
# ls
00-installer-config.yaml

# vi 00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    enp1s0:
      addresses:
      - 192.168.199.210/24
      gateway4: 192.168.199.254
      nameservers:
        addresses:
        - 192.168.199.254
      routes:
          #      - to: 10.200.0.0/24
          #        via: 192.168.199.210
      - to: 10.200.1.0/24
        via: 192.168.199.211
      - to: 10.200.2.0/24
        via: 192.168.199.212
  version: 2
```

適用します。

```shell-session
# netplan apply

# ip route
default via 192.168.199.254 dev enp1s0 proto static
10.200.1.0/24 via 192.168.199.211 dev enp1s0 proto static
10.200.2.0/24 via 192.168.199.212 dev enp1s0 proto static
192.168.199.0/24 dev enp1s0 proto kernel scope link src 192.168.199.210
```

10.200.1.0/24, 10.200.2.0/24 が追加されていることがわかります。
作業は以上で終了です。　以下は細かい補足なので興味があればどうぞ。

---


##インターフェース/ルーティングテーブル関連の補足
ルーティング追加は上記でよいですが、　POD を作成するとどう変わるかを見ておきましょう。

k8sworker0 に上記ルーティング設定をした後の インターフェースの状況は以下のようになっています。

```shell-session
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:a9:a0:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.199.210/24 brd 192.168.199.255 scope global enp1s0
       valid_lft forever preferred_lft forever
```

ループバックを除くと enp1s0 のみです。

ここで、k8sworker0 上で POD ができたときにどうなるかを見てみます。

busybox の Pod を立ててみました。
（手順略...　deployment で replica 3 に指定すれば多分どの worker にも乗るでしょう的な...まぁ手抜きです。）

```shell-session
# kubectl get pods -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
busybox-c44c795b6-kqx5v    1/1     Running   0          14m   10.200.1.141   k8sworker1   <none>           <none>
busybox-c44c795b6-r2qk9    1/1     Running   0          14m   10.200.0.3     k8sworker0   <none>           <none>
busybox-c44c795b6-vsmpb    1/1     Running   0          14m   10.200.2.216   k8sworker2   <none>           <none>
```

さて、 インターフェースですが、以下のように cnio0 と vethXX ができています。
なお、 cnio0 は POD から接続される bridge で、1個だけですが、 vethXX は POD ごとに1個作成されます。
POD削除時には、vethXX は消えますが、POD をすべて消しても cnio0 は残るようです。


```shell-session
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:a9:a0:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.199.210/24 brd 192.168.199.255 scope global enp1s0
       valid_lft forever preferred_lft forever
3: cnio0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether ba:a2:c1:d2:ec:ad brd ff:ff:ff:ff:ff:ff
    inet 10.200.0.1/24 brd 10.200.0.255 scope global cnio0
       valid_lft forever preferred_lft forever
8: vethda1293e1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cnio0 state UP group default
    link/ether d2:4a:ce:16:16:67 brd ff:ff:ff:ff:ff:ff link-netns cni-9b15f61b-eca0-0ded-9dd3-19ac3306daba
```

ルーティングテーブル上には、 k8sworker0 の POD_CIDR (10.200.0.0/24) が cnio0 に行くようになっています。
これが図でいう③の部分に該当します。
実際には iptables で NAT されているようなのですが、ここでは割愛します。
余力があれば別途確認しま。。。す。。　かもしれない？

```shell-session
# ip route
default via 192.168.199.254 dev enp1s0 proto static
10.200.0.0/24 dev cnio0 proto kernel scope link src 10.200.0.1
10.200.1.0/24 via 192.168.199.211 dev enp1s0 proto static
10.200.2.0/24 via 192.168.199.212 dev enp1s0 proto static
192.168.199.0/24 dev enp1s0 proto kernel scope link src 192.168.199.210
```

さらにさらに、 作成した POD の中のインターフェースを見てみると
`eth0@if8` となっています。  この if8 が、　ワーカーノード上の `ip addr` で表示される番号と対応しています。
また、 `8: vethda1293e1@if3` の if3 が  `3: cnio0` とつながっている、という感じで追いかけることができます。
（なぜ 8 なの、という話ですが、 POD を作った際に次の番号がどんどんふられていき、 
POD を消すとインターフェースもきえるため歯抜けになっていくんですね。 
簡単に POD を立てます、とか言いつつ、 4-7 は失敗してやり直したわけだな、と思われてしまうわけですね）


```shell-session
# kubectl exec -it busybox-c44c795b6-r2qk9 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether 4e:46:66:bd:b5:7f brd ff:ff:ff:ff:ff:ff
    inet 10.200.0.3/24 brd 10.200.0.255 scope global eth0
       valid_lft forever preferred_lft forever
```

ネットワークについても少しはイメージがわきましたね。わいたはずです。わいたことにしてください。

---
#エラー・並びに調査・対応方法

さて、恒例の ~~黒歴史~~ トラブル内容紹介です。
先に何を間違えたのかを記載しておくと

- そもそもマスターでやっていた（論外）
- ルーティング設定で自分の POD_CIDR も 自分の NIC に転送するよう設定した

1点は、後から考えるとおバカだな、ぐらいの話しではありますが
実際にやっている最中はなかなか気づきません（と言い訳させてください）

2点目です。

ネットワークの設定完了後、疎通できるかどうかを確認すると思います。その途中で NW 疎通ができないことがわかりました。
調査の実施内容は以下の通りです。
結果を見ると、かなり遠回りしている印象ですが、実際の障害の時はそんなものかな、という気もします。
NW 疎通がおかしいなら、 自分が実施した NW 設定（ここではルーティング）がおかしい、と
考えることができれば早かったかもしれません。
（ただ、kubernetes the hard way を見ると、3つのルーティング設定が同列に扱われているように見えるので
　オンプレでのルーティング設定もそうなんだろうとの思い込みがありました。。。）

1. 各ノードへのPOD の配置 (deployment の作成)
2. POD 内から別ノード上のPOD への ping 疎通　（異常の確認）
3. POD 内から POD のデフォルトゲートウェイへの疎通確認
4. POD 外から別ノード上の cnio0 （POD_CIDR のGW IP）への疎通確認

疎通ができないことがわかれば、あとはどこまで届いているのかを1つずつ確認していくことになりますが
その際に、上図のような構成が頭にないと分からない、ということになります。

## POD の準備

3ノードの上にそれぞれ busybox の POD を立てて、疎通を確認しますが、
簡単に実施するのであれば deployment を作成し、 replica 数を増やせば各ノードに配置されると思います。
作成方法は `kubectl apply -f ファイル名` で。
なお、 v1.16 であれば、 `kubectl run busybox --image=busybox --restart=Always --replicas=3 -o yaml --dry-run --command -- sleep 3600` で yaml ファイルを生成できます（というか、`--dry-run` を外せば作成される）が、 v1.18 ではこのコマンドは使えず、 `kubectl create deployment` をベースとして yaml ファイルを作成する必要があります。
ここは面倒なところですね。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: busybox
  name: busybox
spec:
  replicas: 3
  selector:
    matchLabels:
      run: busybox
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: busybox
    spec:
      containers:
      - command:
        - sleep
        - "3600"
        image: busybox
        name: busybox
        resources: {}
status: {}
```

Pod が出来たら、 `kubectl get pods -o wide` で、調べたいノード上の POD を確認します。（IPも出ています）

```shell-session
# kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
busybox-c44c795b6-5rg4h   1/1     Running   0          10s   10.200.2.218   k8sworker2   <none>           <none>
busybox-c44c795b6-btf4v   1/1     Running   0          10s   10.200.1.143   k8sworker1   <none>           <none>
busybox-c44c795b6-wh2cw   1/1     Running   0          10s   10.200.0.5     k8sworker0   <none>           <none>
```

## Pod 内からの確認

これは定番なので覚えておきましょう。

```shell-session
# kubectl exec -it busybox-c44c795b6-wh2cw /bin/sh
/ #
```

IP / route を確認します。

```shell-session
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    link/ether aa:f3:e9:62:35:2c brd ff:ff:ff:ff:ff:ff
    inet 10.200.0.5/24 brd 10.200.0.255 scope global eth0
       valid_lft forever preferred_lft forever

/ # ip route
default via 10.200.0.1 dev eth0
10.200.0.0/24 dev eth0 scope link  src 10.200.0.5
/ #
```

自分自身への ping 確認(記載省略)ののち、　デフォルトゲートウェイへの ping を行います。

```shell-session
/ # ping 10.200.0.1
PING 10.200.0.1 (10.200.0.1): 56 data bytes
^C
--- 10.200.0.1 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss
```

飛んでいません。　いろいろと調べてわからない状態が続くと、
「もしかしてコンテナの世界ではデフォルトゲートウェイには ping が飛ばないのが普通なのでは？」などという
妄想がわいてきますがそんなことはありません。
疲れているとおかしなことを考えてしまうものです。そういう時は休みましょう。

デフォルトゲートウェイへの ping が飛ばない状態ですが、
コンテナ内の  `ip addr` や `ip route` にそんなにおかしいようには思えない。

そのため、一旦コンテナの中には問題ないと仮定して、外からの確認に移ります。

## POD 外からの確認

k8sworker0 の OS 上から他のノードの POD にアクセスできるかを確認します。
k8sworker0 から k8sworker1,2 の cni0 (それぞれ 10.200.1.1, 10.200.2.1 ) に ping し、応答があります。

```shell-session
root@k8sworker01:/etc/cni/net.d# ping 10.200.1.1
PING 10.200.1.1 (10.200.1.1) 56(84) bytes of data.
64 bytes from 10.200.1.1: icmp_seq=1 ttl=64 time=0.762 ms
64 bytes from 10.200.1.1: icmp_seq=2 ttl=64 time=0.294 ms
64 bytes from 10.200.1.1: icmp_seq=3 ttl=64 time=0.324 ms
^C
--- 10.200.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2047ms
rtt min/avg/max/mdev = 0.294/0.460/0.762/0.213 ms


root@k8sworker01:/etc/cni/net.d# ping 10.200.2.1
PING 10.200.2.1 (10.200.2.1) 56(84) bytes of data.
64 bytes from 10.200.2.1: icmp_seq=1 ttl=64 time=0.516 ms
64 bytes from 10.200.2.1: icmp_seq=2 ttl=64 time=0.408 ms
64 bytes from 10.200.2.1: icmp_seq=3 ttl=64 time=0.252 ms
^C
--- 10.200.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2031ms
rtt min/avg/max/mdev = 0.252/0.392/0.516/0.108 ms

```

ここまでで、　他のノードに関する通信は問題が無いことがわかります。
他のノードへの通信が問題なく、自ノード（のコンテナ）のみに疎通異常がある、ということで
その転送を行っている iptables を疑うわけですが、、、

- そもそも iptables がおかしい (kubernetes による iptables のコントロールがおかしい) などということがあるだろうか？

と考え、それよりも自分の設定がおかしいと考えるほうが可能性が高い、と思い、ルーティングテーブルを確認しました。

```shell-session
root@k8sworker01:# ip route show
default via 192.168.199.254 dev enp1s0 proto static
10.200.0.0/24 via 192.168.199.211 dev enp1s0 proto static
10.200.0.0/24 dev cnio0 proto kernel scope link src 10.200.0.1
10.200.1.0/24 via 192.168.199.212 dev enp1s0 proto static
10.200.2.0/24 via 192.168.199.213 dev enp1s0 proto static
192.168.199.0/24 dev enp1s0 proto kernel scope link src 192.168.199.211
```

10.200.0.0/24 (自ノードの POD_CIDR) へのルートが重複していますね。
ここがおかしいのではないか？となります。

（なお、最初に POD を起動するまでは、  cnio0 に関するルートが無い、下記のような状態なので気づきませんでした
　kubernetes the hard way の [Provisioning Pod Network Routes](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/11-pod-network-routes.md) を見ると、　
下記のようなルーティングテーブルもなんとなく正しく思えます。。。

```shell-session
※間違い
# ip route show
default via 192.168.199.254 dev enp1s0 proto static
10.200.0.0/24 via 192.168.199.211 dev enp1s0 proto static
10.200.1.0/24 via 192.168.199.212 dev enp1s0 proto static
10.200.2.0/24 via 192.168.199.213 dev enp1s0 proto static
192.168.199.0/24 dev enp1s0 proto kernel scope link src 192.168.199.211
```

間違いに気づけば、あとは netplan のルーティング設定を見直して修正し、
問題解消を確認しました。
（ 設定ファイルで 3台分入れて、自ノード分をコメントアウトしているのは
効率を考えたわけではなく、最初は3つ設定していた、ということなんですね。。。）　

---
今回はここまでとして、次回は CoreDNS の部分を実施します。


← [１２．kubectl](https://qiita.com/shimauma_Zzzzz/items/a45b0221710f0ee89e94)
↑ [目次](https://qiita.com/shimauma_Zzzzz/items/84ecf5c748ceafd05380#%E8%AA%AC%E6%98%8E%E8%A8%98%E4%BA%8B%E7%9B%AE%E6%AC%A1)
→ [１４．CoreDNS](https://qiita.com/shimauma_Zzzzz/items/d63d9a9819b3183391ec)

----