Amazon VPC CNI plugin for KubernetesのソースコードリーディングでEKSのネットワーキングについて理解を深める #1

## はじめに

この記事は[Amazon EKS Advent Calendar 2019](https://qiita.com/advent-calendar/2019/amazon-eks) 11日目の記事です。

1. Amazon VPC CNI plugin for KubernetesのソースコードリーディングでEKSのネットワーキングについて理解を深める #1 （**イマココ**）
2. [Amazon VPC CNI plugin for KubernetesのソースコードリーディングでEKSのネットワーキングについて理解を深める #2](https://qiita.com/jlandowner/items/e911dae7d4374c260501)
3. [Amazon VPC CNI plugin for KubernetesのソースコードリーディングでEKSのネットワーキングについて理解を深める #3](https://qiita.com/jlandowner/items/34e834b1dbe1fe7e8ed0)

巷ではEKSにNodeGroupを作成するAPIが追加されたり、FargateがGAになったりと新機能が話題ですが、
今回はそんな新機能には全く触れず、原点に立ち返って、EKSのネットワークの特徴でもある、Amazon VPC CNIプラグイン(amazon-vpc-cni-k8s)について見ていきたいと思います。

自分は長らくEKSでKubernetesを触っていましたが、正直ネットワーク周りをあまり理解していませんでした。
ただKubernetesを触る以上そろそろネットワークのこともちゃんと知っておかないとと思い、改めてEKSのネットワーキングについてまとめたいと思います。

また先に謝らせていただくと、長くなったので実際にソースコードを見ていくのは#2で行います。
CNIプラグインのソースコードまで目を通してみると、Operator SDKや自前のコントローラーがあったり、RWMutexでインメモリデータストアが実装されていたりなど、ネットワークだけでなく色々と発見があって面白いです。


そんな感じでまとまるか少々不安ですが、少しでもどなたかのご参考になれば幸いです。

## Amazon VPC CNI pluginの概要

まずはEKSのドキュメントから。
>ポッドネットワーキング (CNI)
>https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/pod-networking.html


>Amazon EKS は、Amazon VPC CNI plugin for Kubernetes を経由してネイティブな VPC ネットワーキングをサポートします。この CNI プラグインを使用すると、Kubernetes ポッドは VPC ネットワーク上と同じ IP アドレスをポッド内に持つことができます。この CNI プラグインは、GitHub で管理されているオープンソースのプロジェクトです。
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/eaed5f5d-d6dd-eaf1-42e5-c629bd162982.png)

正式名称は「Amazon VPC CNI plugin for Kubernetes」。
Githubのリポジトリはこちら→　https://github.com/aws/amazon-vpc-cni-k8s

Amazon VPC CNIプラグインはEKSのデフォルトCNIプラグインですが、EKS以外にも利用することが可能です。

>Creating a single control-plane cluster with kubeadm
>https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#tabs-pod-install-1

>AWS VPC CNI provides native AWS VPC networking to Kubernetes clusters.

自分も一度kubeadmで構築したことがあります。以前はバグに当たったりなどHard wayな印象でしたが、EKSのネットワークに興味ある人は是非。

ただ、そんなところに興味もなかった昔の自分は、

「ENIのセカンダリIPなるものがPodに割り振られるらしい。だからクラスタ外からもPodのIPに直接繋がるらしい。」

そんな程度の理解でした。


### ENIのセカンダリIPについて

ところでENIって意外と何者かわからなくないでしょうか(少なくとも自分はわかりませんでした)

しかもENIのセカンダリIPについては、特にネット上の情報が少ない印象です。

>複数の IP アドレス
>https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/MultipleIP.html

ENIはEC2等にアタッチ可能な仮想ネットワークインターフェースです。実態はよく分かりませんが、MACアドレスを動的に割り当てる仕組みなのでしょうか。

ENIには複数のIPアドレスを割り当てることが可能で、１つのプライマリIPと、複数のセカンダリIPを持つことができます。

このようなENIの特徴のうち、Amazon VPC CNIプラグインにとって重要なことは、「ENIのセカンダリIPはEC2内で割り振り直すことができる」ということです。これを利用することで、VPCネイティブなPodネットワーキングを実現しています。

>セカンダリプライベート IPv4 アドレスを認識するようにインスタンスのオペレーティングシステムを設定する
>https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/MultipleIP.html

>セカンダリプライベート IPv4 アドレスをインスタンスに割り当てたら、セカンダリプライベート IP アドレスを認識するようにインスタンスのオペレーティングシステムを設定する必要があります。
>ネットワークインターフェイスに割り当てられているセカンダリプライベート IPv4 アドレスは、明示的に許可された場合、別のネットワークインターフェイスに割り当て直すことができます。

ENIやセカンダリIPはEC2インスタンスタイプごとに割り当て可能な量に違いがあります。そのためEKSのノードで動かせるPod数は、CPUやメモリといったリソースのほかに、IPアドレス数の制限を受けます。

### CNIプラグインのコンポーネント

次にCNIプラグインがどのような構成なのか見ていきます。
先ほどのEKSのドキュメントの続きをみます。

>https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/pod-networking.html

>CNI プラグインは、Kubernetes ノードに VPC IP アドレスを割り当て、各ノードのポッドに必要なネットワークを設定します。​このプラグインは 2 つの主なコンポーネントで構成されています。

>- L-IPAM デーモンは、インスタンスへの Elastic Network Interface の接続、Elastic Network Interface へのセカンダリ IP アドレスの割り当て、スケジュールされた際に Kubernetes ポッドに割り当てるために各ノードにおける IP アドレスの「ウォームプール」の維持を行います。

>- CNI プラグインは、ホストネットワークの接続 (例: インターフェイスと仮想イーサネットペアの設定) とポッド名前空間への正しいインターフェイスの追加を行います。

`L-IPAMデーモン`(Local IP Address Manager Daemon、ipamdとの記載もあります)は、各ノードで`aws-node`というdaemonsetのPodで起動します。L-IPAMは内部にデータストアをもち、IPアドレスの管理やPodへのアサインを行っています。gRPCサーバの機能ももち、CNIプラグインからのPodの追加／削除リクエストに応えます。

`CNIプラグイン`は、その名の通り、CNIの仕様に沿って実行されるモジュールで、gRPCでL-IPAMと通信してIPを取得し、ネットワーク設定を行います。以下、公式のイメージを引用します。

>Inter-process communication between CNI-plugin and L-IPAM
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md#inter-process-communication--between-cni-plugin-and-l-ipam
><img width="959" alt="ipam.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/6aabd1d3-1165-011b-4b72-ff00968b90da.png">
(Officeでちょろっと作ったような図ですよね・・・笑)


そもそもCNIって・・・という方には以下の記事が参考になります。

>CNCF CNI プラグイン
>https://qiita.com/hichihara/items/54ff9aeff476bf463509

## EKSクラスター作成時の状態

それでは実際にEKSの状態を見ていきましょう。

### クラスターの状態
まずはkubectlでクラスターの状態から。

```console
$ kubectl get nodes
NAME                                               STATUS   ROLES    AGE   VERSION
ip-10-110-10-171.ap-northeast-1.compute.internal   Ready    <none>   8h    v1.14.7-eks-1861c5
ip-10-110-10-233.ap-northeast-1.compute.internal   Ready    <none>   9d    v1.14.7-eks-1861c5
ip-10-110-20-254.ap-northeast-1.compute.internal   Ready    <none>   8d    v1.14.7-eks-1861c5
```

```console
$ kubectl get all -n kube-system -l k8s-app=aws-node -o wide
NAME                 READY   STATUS    RESTARTS   AGE   IP              NODE                                               NOMINATED NODE   READINESS GATES
pod/aws-node-2gl8m   1/1     Running   0          16h   10.110.10.171   ip-10-110-10-171.ap-northeast-1.compute.internal   <none>           <none>
pod/aws-node-v8w76   1/1     Running   0          9d    10.110.10.233   ip-10-110-10-233.ap-northeast-1.compute.internal   <none>           <none>
pod/aws-node-xpqxv   1/1     Running   0          9d    10.110.20.254   ip-10-110-20-254.ap-northeast-1.compute.internal   <none>           <none>

NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE   CONTAINERS   IMAGES                                                                    SELECTOR
daemonset.apps/aws-node   3         3         3       3            3           <none>          14d   aws-node     602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni:v1.5.3   k8s-app=aws-node

$ kubectl describe daemonset.apps/aws-node -n kube-system
Name:           aws-node
Selector:       k8s-app=aws-node
Node-Selector:  <none>
Labels:         k8s-app=aws-node
Annotations:    deprecated.daemonset.template.generation: 1
                kubectl.kubernetes.io/last-applied-configuration:{}
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Scheduled with Up-to-date Pods: 3
Number of Nodes Scheduled with Available Pods: 3
Number of Nodes Misscheduled: 0
Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:           k8s-app=aws-node
  Service Account:  aws-node
  Containers:
   aws-node:
    Image:      602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni:v1.5.3
    Port:       61678/TCP
    Host Port:  61678/TCP
    Requests:
      cpu:  10m
    Environment:
      AWS_VPC_K8S_CNI_LOGLEVEL:  DEBUG
      MY_NODE_NAME:               (v1:spec.nodeName)
    Mounts:
      /host/etc/cni/net.d from cni-net-dir (rw)
      /host/opt/cni/bin from cni-bin-dir (rw)
      /host/var/log from log-dir (rw)
      /var/run/docker.sock from dockersock (rw)
  Volumes:
   cni-bin-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /opt/cni/bin
    HostPathType:  
   cni-net-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /etc/cni/net.d
    HostPathType:  
   log-dir:
    Type:          HostPath (bare host directory volume)
    Path:          /var/log
    HostPathType:  
   dockersock:
    Type:          HostPath (bare host directory volume)
    Path:          /var/run/docker.sock
    HostPathType:  
Events:            <none>
```
`aws-node`というdaemonsetが起動します。いつも見るやつですね。
この中でL-IPAMが動いています。

このPodのIPは各ノードのプライマリIPとなっており、HostPathでいくつかホスト上のディレクトリをマウントしていることがわかります。



また、CRDが１つ作成されています。

```console
$ kubectl api-resources # 抜粋
NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND
eniconfigs                                     crd.k8s.amazonaws.com          false        ENIConfig
```

これは、Podのネットワークに、同じVPC内にある別のセキュリティグループまたはサブネットを使用したい場合にオプションで利用します。
今回は詳しく触れませんので、公式ドキュメントを貼っておきます。

>CNI カスタムネットワーク
>https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cni-custom-network.html

### ノードの状態

ノードにログインして、先ほど確認した、`aws-node`にHostPathでマウントしているディレクトリを見ていきましょう。

**cni-bin-dir:**
cniで利用される実行ファイルが配置されたディレクトリです。kubeletの起動オプションで変えられた気がしますが、マウントされているのはデフォルトで利用されるディレクトリです。

EKSのドキュメントに記載のあったCNIプラグインが`aws-cni`というモジュールです。
CNIの仕様に沿って実行され、ipamdとgRPCで通信します。

```console
$ ll /opt/cni/bin
合計 69688
-rwxr-xr-x 1 root root 15863452 11月 28 00:12 aws-cni <---------- これ
-rwxr-xr-x 1 root root     3110 11月 28 00:12 aws-cni-support.sh
-rwxr-xr-x 1 root root  4028260  3月 15  2019 bridge
-rwxr-xr-x 1 root root  2775211  8月 17  2017 cnitool
-rwxr-xr-x 1 root root 10232415  3月 15  2019 dhcp
-rwxr-xr-x 1 root root  2856252  3月 15  2019 flannel
-rwxr-xr-x 1 root root  3127363  3月 15  2019 host-device
-rwxr-xr-x 1 root root  3036768  3月 15  2019 host-local
-rwxr-xr-x 1 root root  3572685  3月 15  2019 ipvlan
-rwxr-xr-x 1 root root  3084347  3月 15  2019 loopback
-rwxr-xr-x 1 root root  3613497  3月 15  2019 macvlan
-rwxr-xr-x 1 root root  2606733  8月 17  2017 noop
-rwxr-xr-x 1 root root  3470464 11月 28 00:12 portmap
-rwxr-xr-x 1 root root  3993428  3月 15  2019 ptp
-rwxr-xr-x 1 root root  2641877  3月 15  2019 sample
-rwxr-xr-x 1 root root  2850029  3月 15  2019 tuning
-rwxr-xr-x 1 root root  3568537  3月 15  2019 vlan
```

なお、`aws-cni-support.sh`はデバッグ用の情報収集ツールです。Githubにほんの少しドキュメントがあります。

>Troubleshooting Tips
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/troubleshooting.md

>collecting node level tech-support bundle for offline troubleshooting
>[root@ip-192-168-188-7 aws-routed-eni]# /opt/cni/bin/aws-cni-support.sh 

>// download
>/var/log/aws-routed-eni/aws-cni-support.tar.gz


**cni-net-dir:** 
CNIの設定を記載したConfigファイルを配置するディレクトリです。
このディレクトリにConfigファイルを配置することで、NodeStatus が Ready になります。

中身には、先ほどの`aws-cni`をCNIプラグインとして使うことなどが記載されています。

```console
$ ll /etc/cni/net.d
合計 4
-rw-r--r-- 1 root root 235 11月 28 00:12 10-aws.conflist
$ cat /etc/cni/net.d/10-aws.conflist
{
  "name": "aws-cni",
  "plugins": [
    {
      "name": "aws-cni",
      "type": "aws-cni",
      "vethPrefix": "eni"
    },
    {
      "type": "portmap",
      "capabilities": {"portMappings": true},
      "snat": true
    }
  ]
}
```

**log-dir:**
ipamdやCNIプラグインのログが出力されています。
1時間ごと1日24ファイルも作っているんですね・・・

```console
$ ll /var/log/aws-routed-eni/
合計 14992
-rw-r--r-- 1 root root 628617 12月  7 00:59 ipamd.log.2019-12-07-00
-rw-r--r-- 1 root root 629027 12月  7 01:59 ipamd.log.2019-12-07-01
-rw-r--r-- 1 root root 629018 12月  7 02:59 ipamd.log.2019-12-07-02
-rw-r--r-- 1 root root 629020 12月  7 03:59 ipamd.log.2019-12-07-03
-rw-r--r-- 1 root root 628943 12月  7 04:59 ipamd.log.2019-12-07-04
-rw-r--r-- 1 root root 629025 12月  7 05:59 ipamd.log.2019-12-07-05
-rw-r--r-- 1 root root 629041 12月  7 06:59 ipamd.log.2019-12-07-06
-rw-r--r-- 1 root root 628617 12月  7 07:59 ipamd.log.2019-12-07-07
-rw-r--r-- 1 root root 629048 12月  7 08:59 ipamd.log.2019-12-07-08
-rw-r--r-- 1 root root 629023 12月  7 09:59 ipamd.log.2019-12-07-09
-rw-r--r-- 1 root root 629024 12月  7 10:59 ipamd.log.2019-12-07-10
-rw-r--r-- 1 root root 628920 12月  7 11:59 ipamd.log.2019-12-07-11
-rw-r--r-- 1 root root 629033 12月  7 12:59 ipamd.log.2019-12-07-12
-rw-r--r-- 1 root root 629013 12月  7 13:59 ipamd.log.2019-12-07-13
-rw-r--r-- 1 root root 628607 12月  7 14:59 ipamd.log.2019-12-07-14
-rw-r--r-- 1 root root 629030 12月  7 15:59 ipamd.log.2019-12-07-15
-rw-r--r-- 1 root root 181262 12月  7 16:17 ipamd.log.2019-12-07-16
-rw-r--r-- 1 root root   1718 11月 28 00:21 plugin.log.2019-11-28-00
-rw-r--r-- 1 root root   4585 11月 28 04:32 plugin.log.2019-11-28-04
-rw-r--r-- 1 root root   3253 12月  5 01:13 plugin.log.2019-12-05-01
```

**dockersock:**
Dockerのsocketですね。


## ENIを通してPodが繋がる仕組み

EC2内でどのようなルーティング設定を行っているのかは、Githubにドキュメントがあります。

>Proposal: CNI plugin for Kubernetes networking over AWS VPC
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md

>Pod to Pod Communication
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md#pod-to-pod-communication
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/93d4903b-6779-8cda-98d6-2e513f88f267.png)

ホスト側でvethを作成し、Podのネットワーク名前空間のeth0に紐づけています。

そしてPodに割り当てたENIのセカンダリIPにきた通信が、vethに流れるようにルーティングテーブルを設定することで、Podに繋がるようになっています。

>Life of a Pod to Pod Ping Packet
https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md#life-of-a-pod-to-external-packet

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279529/2bacf843-f9d4-a3a6-d352-a4d476bfd42f.png)

Podから外への通信は、Podのネットワーク名前空間のデフォルトゲートウェイからvethに流れるようにして実現しているようです。

## Pod起動時の状態

実際にPodを起動してノードの中身を見てみます。
何度目の引用かわかりませんが、実際のネットワーク設定が書いてある貴重なドキュメントなので、これに沿って見ていきます。

>Pod to Pod Communication
>inside-a-pod
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md#inside-a-pod

>on-host-side
>https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/cni-proposal.md#on-host-side


Podとしてnetshootを起動しました。PodのIPは `10.110.10.109` です。

>nicolaka/netshoot
>https://github.com/nicolaka/netshoot

```console
$ kubectl get po tmp-shell -o wide 
NAME        READY   STATUS    RESTARTS   AGE   IP              NODE                                               NOMINATED NODE   READINESS GATES
tmp-shell   1/1     Running   0          13h   10.110.10.109   ip-10-110-10-171.ap-northeast-1.compute.internal   <none>           <none>
```

ノードにログインして動いているdockerコンテナを確認します。

このノードで動いているのは、kube-proxyとaws-nodeと各pauseコンテナをのぞいて、netshootのコンテナだけです。
（pauseコンテナは、Podのネットワーク名前空間を保持するコンテナです。仮にアプリのコンテナが再起動してもネットワーク名前空間が再利用できるよう存在します。）

```console
[ec2-user@ip-10-110-10-171 ~]$ sudo docker ps
CONTAINER ID        IMAGE                                                                   COMMAND                  CREATED             STATUS              PORTS               NAMES
e49972815e64        932520758690.dkr.ecr.ap-northeast-1.amazonaws.com/nicolaka/netshoot     "tail -f /dev/null"      13 hours ago        Up 13 hours                             k8s_tmp-shell_tmp-shell_kube-system_de9cb72e-1a90-11ea-a80c-0efdaea6eca6_0 <---------- これと
373b7e98b5a1        602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/eks/pause-amd64:3.1   "/pause"                 13 hours ago        Up 13 hours                             k8s_POD_tmp-shell_kube-system_de9cb72e-1a90-11ea-a80c-0efdaea6eca6_0 <---------- これ
13e3eed03049        602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/amazon-k8s-cni        "/bin/sh -c /app/ins…"   3 days ago          Up 3 days                               k8s_aws-node_aws-node-2gl8m_kube-system_b0160f05-1806-11ea-b040-0adab48a968a_0
9fec891354e8        602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/eks/kube-proxy        "kube-proxy --v=2 --…"   3 days ago          Up 3 days                               k8s_kube-proxy_kube-proxy-6wjkw_kube-system_b0169b30-1806-11ea-b040-0adab48a968a_0
4bfccfc27c3d        602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/eks/pause-amd64:3.1   "/pause"                 3 days ago          Up 3 days                               k8s_POD_aws-node-2gl8m_kube-system_b0160f05-1806-11ea-b040-0adab48a968a_0
0b6435826e81        602401143452.dkr.ecr.ap-northeast-1.amazonaws.com/eks/pause-amd64:3.1   "/pause"                 3 days ago          Up 3 days                               k8s_POD_kube-proxy-6wjkw_kube-system_b0169b30-1806-11ea-b040-0adab48a968a_0
[ec2-user@ip-10-110-10-171 ~]$ 
```

このノードにはENIが２つアタッチされていました。
一番最後のネットワークインターフェースがPod用のvethです。

```console
[ec2-user@ip-10-110-10-171 ~]$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 06:a3:0c:9d:99:5e brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 06:ed:bb:fd:5a:d8 brd ff:ff:ff:ff:ff:ff
6: enie5da25cfd1a@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP mode DEFAULT group default <---------- Podのveth
    link/ether 02:5b:59:7b:c9:f7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
```

```console
[ec2-user@ip-10-110-10-171 ~]$ 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:a3:0c:9d:99:5e brd ff:ff:ff:ff:ff:ff
    inet 10.110.10.171/24 brd 10.110.10.255 scope global dynamic eth0 <---------- ENI(eth0)プライマリIP
       valid_lft 3339sec preferred_lft 3339sec
    inet6 fe80::4a3:cff:fe9d:995e/64 scope link 
       valid_lft forever preferred_lft forever
4: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:ed:bb:fd:5a:d8 brd ff:ff:ff:ff:ff:ff
    inet 10.110.10.167/24 brd 10.110.10.255 scope global eth1 <---------- ENI(eth1)のプライマリIP
       valid_lft forever preferred_lft forever
    inet6 fe80::4ed:bbff:fefd:5ad8/64 scope link 
       valid_lft forever preferred_lft forever
6: enie5da25cfd1a@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
    link/ether 02:5b:59:7b:c9:f7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::5b:59ff:fe7b:c9f7/64 scope link 
       valid_lft forever preferred_lft forever
```

次にルーティング設定を見てみます。
ルールを確認すると、`10.110.10.109`への通信はmainルートテーブルを見なさいとあります。

```console
[ec2-user@ip-10-110-10-171 ~]$ ip rule
0:      from all lookup local 
512:    from all to 10.110.10.109 lookup main 
1024:   from all fwmark 0x80/0x80 lookup main 
32766:  from all lookup main 
32767:  from all lookup default 
```

mainルートテーブルをみます。
`10.110.10.109`は`enie5da25cfd1a`を使いなさいとあります。
これがPodのvethですね。その他の通信はeth0を使うようになっています。

```console
[ec2-user@ip-10-110-10-171 ~]$ ip route show table main
default via 10.110.10.1 dev eth0 
10.110.10.0/24 dev eth0 proto kernel scope link src 10.110.10.171 
10.110.10.109 dev enie5da25cfd1a scope link 
169.254.169.254 dev eth0
```

先ほどのネットワークインタフェースを見るとvethのMACアドレスが`02:5b:59:7b:c9:f7`とあります。

```console
[ec2-user@ip-10-110-10-171 ~]$ ip link
〜〜
6: enie5da25cfd1a@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:5b:59:7b:c9:f7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
```

それでは次にコンテナ内のネットワーク設定をみてみます。
コンテナのネットワーク名前空間内のeth0のipアドレスが、`10.110.10.109`になっていることがわかります。

```console
[ec2-user@ip-10-110-10-171 ~]$ sudo docker exec e49972815e64 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
3: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default 
    link/ether 62:18:cc:40:63:a8 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.110.10.109/32 brd 10.110.10.109 scope global eth0
```

コンテナ内のルーティングテーブルは`169.254.1.1`がデフォルトゲートウェイになっています。

```console
[ec2-user@ip-10-110-10-171 ~]$ sudo docker exec e49972815e64 ip route
default via 169.254.1.1 dev eth0 
169.254.1.1 dev eth0 scope link 
```

最後に、arpテーブルを見ると、`169.254.1.1`がホスト側のvethのMACアドレス`02:5b:59:7b:c9:f7`に紐づいていることがわかります。

```console
[ec2-user@ip-10-110-10-171 ~]$ sudo docker exec e49972815e64 ip neigh
169.254.1.1 dev eth0 lladdr 02:5b:59:7b:c9:f7 PERMANENT
```

# 最後に

ひとまず今回はドキュメントや実際のクラスターの状態から、ネットワークの基本的な内容を整理しました。

次回はCNIプラグインのソースコードを見ていきますが、ネットワーク周りだけでなくGoの面白そうなところをピックアップしていきたいと思います。