【Kubernetes】 flannel を使ったコンテナ間通信をキャプチャしてみた

Kubernetes (k8s) をデプロイして動作確認をしてみました。Container Networking Interface (CNI) として flannel と Calico の両方を試してみたので、今回は flannel を 利用した場合にノード上のコンテナ間でどのように通信が行われているのか検証した結果をまとめました。

構成

以下のような k8s 環境を構築しました。シングル master とし、Pod 間通信用に NIC を分けています。

f:id:naoki029:20190302210655p:plain

仮想マシンのスペックは以下の通りです。

  • 2 vCPU
  • 3 GB Memory
  • CentOS Linux release 7.6.1810
  • NIC は 2枚
    • NIC1: enp0s3 (Node アクセス、インターネット接続用)
    • NIC2: enp0s8 (Pod 間通信用)

ハイパーバイザーは VirtualBox を使用しています。

k8s の構築

公式ドキュメントを参考に構築を行いました。詳しいインストール方法については解説しません。自分がハマったところだけかいつまんで書いていきます。

k8s インストールの準備として、予め以下の設定を行っておきます。

  • hostname の設定
    • master 1台 : master.lab.com
    • worker 3台 : worker1.lab.com, worker2.lab.com, worker3.lab.com
  • /etc/hosts の編集
[root@master ~]# cat /etc/hosts | grep \.lab\.com
10.0.0.1 master.lab.com
10.0.0.2 worker1.lab.com
10.0.0.3 worker2.lab.com
10.0.0.4 worker3.lab.com
  • SELinux を Permissive に設定
  • swap を無効

上記の設定が終わったら、Docker、k8s のインストールに移ります。

  • Docker のインストール
  • kubelet, kubeadm, kubectl のインストール

これで master / worker ノードの両方に必要なソフトウェアのインストールが完了しました。

引き続き、master ノードで k8sクラスタ設定を行っていきます。

[root@master ~]# kubeadm init --apiserver-advertise-address 10.0.0.1 --pod-network-cidr=10.244.0.0/16
.....
(snip)
You can now join any number of machines by running the following on each node
as root:

  kubeadm join 10.0.0.1:6443 --token ****  --discovery-token-ca-cert-hash ******

[root@master ~]#

--apiserver-advertise-address では、NIC2 が接続している 10.0.0.0/24 のネットワークを利用して k8s ノードの管理用の通信を行うよう指定しています。

--pod-network-cidr は Pod に払い出す CIDR アドレスを指定しています。10.244.0.0/16 としている理由は、この後に行う flannel デプロイのデフォルト設定と一致させるためです。

flannel の設定ファイルをダウンロードし、Pod 間通信用の NIC を指定します。デフォルトでは、 default route を持つ NIC が選択されます。

[root@master ~]# curl -O https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
[root@master ~]# vim kube-flannel.yml
[root@master ~]# cat kube-flannel.yml
---snip---
         command:
         - /opt/bin/flanneld
         args:
         - --iface=enp0s8  #iface オプションを指定
         - --ip-masq
         - --kube-subnet-mgr
         resources:
---snip---
[root@master ~]#

編集した設定を使用して flannel をデプロイします。

[root@master ~]# kubectl apply -f kube-flannel.yml
podsecuritypolicy.extensions/psp.flannel.unprivileged created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.extensions/kube-flannel-ds-amd64 created
daemonset.extensions/kube-flannel-ds-arm64 created
daemonset.extensions/kube-flannel-ds-arm created
daemonset.extensions/kube-flannel-ds-ppc64le created
daemonset.extensions/kube-flannel-ds-s390x created
[root@master ~]#

worker ノードを K8s クラスターに参加させます。

[root@worker1 ~]# kubeadm join 10.0.0.1:6443 --token ***--discovery-token-ca-cert-hash ***** # worker2, worker3 でも実行する。

worker ノードの状態が Ready になっていることが確認できます。

[root@master ~]# kubectl get nodes
NAME              STATUS   ROLES    AGE    VERSION
master.lab.com    Ready    master   31m    v1.13.4
worker1.lab.com   Ready    <none>   102s   v1.13.4
worker2.lab.com   Ready    <none>   98s    v1.13.4
worker3.lab.com   Ready    <none>   95s    v1.13.4
[root@master ~]#

system 用の Pod が全て Running となっていれば、K8s + flannel の環境構築は完了です。

[root@master ~]# kubectl get pods -n kube-system
NAME                                     READY   STATUS    RESTARTS   AGE
coredns-86c58d9df4-2rzz6                 1/1     Running   1          31m
coredns-86c58d9df4-vs4ph                 1/1     Running   1          31m
etcd-master.lab.com                      1/1     Running   0          30m
kube-apiserver-master.lab.com            1/1     Running   0          30m
kube-controller-manager-master.lab.com   1/1     Running   0          30m
kube-flannel-ds-amd64-l94cx              1/1     Running   0          116s
kube-flannel-ds-amd64-vwstv              1/1     Running   0          5m49s
kube-flannel-ds-amd64-xdmnv              1/1     Running   0          113s
kube-flannel-ds-amd64-zcmnw              1/1     Running   0          2m
kube-proxy-5lgpt                         1/1     Running   0          31m
kube-proxy-dzfhm                         1/1     Running   0          116s
kube-proxy-f6tzt                         1/1     Running   0          2m
kube-proxy-mttv2                         1/1     Running   0          113s
kube-scheduler-master.lab.com            1/1     Running   0          30m
[root@master ~]#

flannel を利用した Pod 間の通信確認

以下に示す kube-test.yml を利用して centos のコンテナを3台デプロイし、Pod 間の通信を確認します。

[root@master ~]# cat kube-test.yml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: centos-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: centos
  template:
    metadata:
      labels:
        app: centos
    spec:
      containers:
      - name: centos
        image: centos
        command: ["/bin/sh","-c","while true; do sleep 3600; done"]
[root@master ~]#
[root@master ~]# kubectl apply -f kube-test.yml
deployment.extensions/centos-deployment created

Pod の状態を確認すると、それぞれ別の worker ノードに Pod がデプロイされ、各 Pod に10.244.0.0/16 から Pod ネットワークが払い出されていることが確認できます。

[root@master ~]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP           NODE              NOMINATED NODE   READINESS GATES
centos-deployment-75f6cbcb5d-d7vcb   1/1     Running   0          78s   10.244.3.5   worker3.lab.com   <none>           <none>
centos-deployment-75f6cbcb5d-h22tj   1/1     Running   0          78s   10.244.1.9   worker1.lab.com   <none>           <none>
centos-deployment-75f6cbcb5d-qt7qm   1/1     Running   0          78s   10.244.2.7   worker2.lab.com   <none>           <none>
[root@master ~]#

f:id:naoki029:20190302210818p:plain

worker1 にデプロイされている centos のコンテナから、worker2 のコンテナに ping を実行し各 worker ノードの NIC でコンテナ間のパケットをキャプチャしてみます。キャプチャポイントは以下の4点です。

f:id:naoki029:20190302210857p:plain

  • A : worker1 で動いているコンテナの NIC
  • B : worker1 の NIC
  • C : worker2 の NIC
  • D : worker2 で動いているコンテナの NIC

f:id:naoki029:20190302210922p:plain

キャプチャした結果より、コンテナから送信されたパケットは worker ノードで VXLAN でカプセル化され、宛先コンテナが動いている worker ノードまで転送されていることがわかります。最終的には worker ノードによってカプセル化が解除され、宛先のコンテナに転送されていることが確認できました。

まとめ

CNI に flannel を使用して、K8s クラスタのデプロイを行い、Pod 間の通信がどのような経路で行われているか確認しました。実際には flannel より Calico の方が k8s の CNI として利用されていることが多いようです。Calico に関しても同じような動作確認を行ったので、次は2つの違いも含めてまとめてみようと思います。