😊

Kubernetes の Service (Cluster IP) がどう実装されてるか

2022/04/29に公開
2

まぁ 1 行で表すなら iptables でできてます。(ほんとは kube-proxy で構成されていて、それが iptables モードで動いてることがおおい、ということらしい。ご指摘ありがとうございます。)
ここ に iptables プロキシーモードについて書いてあった。
Service の中でも Cluster IP のやつです。
それを少し深堀りしてみる。

今回は kube-dns を構成している Service について調べていっています。

$ kubectl get svc kube-dns -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   12d

この 10.0.0.10 がどう扱われて coredns の pod に行ってるか、という話です。

まずは普通に iptables を叩くんですが、これがまたはまりポイントがあって、適当な pod ではたたけなくて、kube-proxy pod で叩く必要があるらしい。
むずかしいねぇ。

ここでは、nat テーブルを見に行ってみます。
それぞれ示しているのは抜粋なので、全体としてはもっとすごい長いです。

$ kubectl exec -it kube-proxy-wf7qw -n kube-system -- iptables -nL -t nat --line-numbers
Chain KUBE-SERVICES (2 references)
num  target     prot opt source               destination
5    KUBE-MARK-MASQ  udp  -- !172.16.10.0/24       10.0.0.10            /* kube-system/kube-dns:dns cluster IP */ udp dpt:53
6    KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  0.0.0.0/0            10.0.0.10            /* kube-system/kube-dns:dns cluster IP */ udp dpt:53

KUBE-MARK-MASQ はマークつけるだけなので次行きます。

Chain KUBE-MARK-MASQ (16 references)
num  target     prot opt source               destination
1    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000

KUBE-SVC-TCOU7JCQXEZGVUNU が Service の実体ともいえるものっぽい。
iptablesstatistic という Load Balancer 的な extention を使って 1/2 の確率で 1 行目にパケットを飛ばし、のこりは 2 行目に流し込みます。

Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
num  target     prot opt source               destination
1    KUBE-SEP-K7EZDDI5TWNJA7RX  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ statistic mode random probability 0.50000000000
2    KUBE-SEP-JTVLMQFBDVPXUWUS  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */

それぞれはこんな感じ。
また KUBE-MARK-MASQ がありますがとりあえず無視して、DNAT (Destination Network Address Translation) されているようです。

Chain KUBE-SEP-K7EZDDI5TWNJA7RX (1 references)
num  target     prot opt source               destination
1    KUBE-MARK-MASQ  all  --  172.16.10.42         0.0.0.0/0            /* kube-system/kube-dns:dns */
2    DNAT       udp  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:172.16.10.42:53

Chain KUBE-SEP-JTVLMQFBDVPXUWUS (1 references)
num  target     prot opt source               destination
1    KUBE-MARK-MASQ  all  --  172.16.10.9          0.0.0.0/0            /* kube-system/kube-dns:dns */
2    DNAT       udp  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:172.16.10.9:53

んで、確かに IP アドレスとしては coredns の IP であることが確認できる。

$ kubectl get po -n kube-system -o wide -l k8s-app=kube-dns
NAME                     READY   STATUS    RESTARTS   AGE    IP             NODE                                NOMINATED NODE   READINESS GATES
coredns-69c47794-6xnlq   1/1     Running   0          18h    172.16.10.9    aks-nodepool1-19344272-vmss000000   <none>           <none>
coredns-69c47794-cgn9k   1/1     Running   0          7d9h   172.16.10.42   aks-nodepool1-19344272-vmss000001   <none>           <none>

じゃあ、ということで coredns を scale out してみる。

$ kubectl edit cm coredns-autoscaler -n kube-system
configmap/coredns-autoscaler edited

kubectl logs はこちら。

$ kubectl logs -l k8s-app=coredns-autoscaler -n kube-systemom 3 to 2
I0429 09:27:35.723958       1 ladder_controller.go:72] Detected ConfigMap version change (old: 3440910 new: 3464256) - rebuilding lookup entries
I0429 09:27:35.723986       1 ladder_controller.go:73] Params from apiserver:
{"coresToReplicas":[[1,2],[512,3],[1024,4],[2048,5]],"nodesToReplicas":[[1,2],[3,3],[16,4],[32,5]]}
I0429 09:27:35.749081       1 k8sclient.go:272] Cluster status: SchedulableNodes[3], SchedulableCores[6]
I0429 09:27:35.749100       1 k8sclient.go:273] Replicas are not as expected : updating replicas from 2 to 3

KUBE-SVC-TCOU7JCQXEZGVUNU に 1 行増えて、probability も約 1/3 ずつに変化している。

$ kubectl exec -it kube-proxy-wf7qw -n kube-system -- iptables -nL -t nat --line-numbers
Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
num  target     prot opt source               destination
1    KUBE-SEP-K7EZDDI5TWNJA7RX  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ statistic mode random probability 0.33333333349
2    KUBE-SEP-DY563SJUKUTESOPF  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ statistic mode random probability 0.50000000000
3    KUBE-SEP-JTVLMQFBDVPXUWUS  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */

追加された KUBE-SEP-DY563SJUKUTESOPF は他のとほとんど違いはない。

Chain KUBE-SEP-DY563SJUKUTESOPF (1 references)
num  target     prot opt source               destination
1    KUBE-MARK-MASQ  all  --  172.16.10.72         0.0.0.0/0            /* kube-system/kube-dns:dns */
2    DNAT       udp  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ udp to:172.16.10.72:53

KUBE-SEP-DY563SJUKUTESOPF の DNAT IP アドレス 172.16.10.72 は新たに増えた coredns pod の IP アドレスであることが確認できます。

$ kubectl get po -l k8s-app=kube-dns -n kube-system -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP             NODE                                NOMINATED NODE   READINESS GATES
coredns-69c47794-6xnlq   1/1     Running   0          19h    172.16.10.9    aks-nodepool1-19344272-vmss000000   <none>           <none>
coredns-69c47794-cgn9k   1/1     Running   0          7d9h   172.16.10.42   aks-nodepool1-19344272-vmss000001   <none>           <none>
coredns-69c47794-mm4rf   1/1     Running   0          2m7s   172.16.10.72   aks-nodepool1-19344272-vmss000008   <none>           <none>

んで、戻す。

$ kubectl edit cm coredns-autoscaler -n kube-system
configmap/coredns-autoscaler edited
$ kubectl exec -it kube-proxy-wf7qw -n kube-system -- iptables -nL -t nat
Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
num  target     prot opt source               destination
1    KUBE-SEP-K7EZDDI5TWNJA7RX  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */ statistic mode random probability 0.50000000000
2    KUBE-SEP-JTVLMQFBDVPXUWUS  all  --  0.0.0.0/0            0.0.0.0/0            /* kube-system/kube-dns:dns */

めでたしめでたし。

Microsoft (有志)

Discussion

Kazuki Suda (@superbrothers)Kazuki Suda (@superbrothers)

まぁ 1 行で表すなら iptables でできてます。

Service を実現しているコンポーネントは kube-proxy なのですが、kube-proxy には userspace (古い)、iptables(デフォルト)、ipvs の3つのモードがあるので、一概に iptables でできているとは言えないのです。ただ知る限りほとんどのクラスタでは iptables モードが選択されています。

近頃は kube-proxy を使わずに CNI プラグインがその役割も持っているものもあり、Calico や Cilium がサポートしています。使われているという話はあまり聞かないです。

Kuberenetes の Service (Cluster IP) がどう実装されてるか

typo されてますねw

skmkzykskmkzyk

おおおーーーーコメントありがとうございます。
kube-proxy の役割についてももう少し読んでみるようにします!

typo されてますねw

いやー e を何個書けばいいかわからくなっちゃうんですよねw 直しておきました!