K8sのServiceの名前解決からkube-proxyのiptablesによってPodにロードバランシングされるまでの流れを追う

kubernetes

Kubernetes の Service は my-svc.my-namespace.svc.cluster-domain.example のような FQDN を持ち、これにリクエストすると selector が指す Pod に届く。これがどのように実現されているかを追う。EKS で立てた Kubernetes 1.28 クラスタで確認する。

まず Service の FQDN から ClusterIP への名前解決は、各 Pod の /etc/resolv.conf の nameserver 設定に従い kube-dns (coredns) へ問い合わせることで行われる。なお、この IP アドレス自体も kube-dns Service の ClusterIP なので以後は同様にルーティングされることになる。

$ cat /etc/resolv.conf
search testapp.svc.cluster.local svc.cluster.local cluster.local ap-northeast-1.compute.internal
nameserver 172.20.0.10
options ndots:5

Service はロードバランシングの機能を提供するが、これは iptables によって実現されている。この iptabels の設定を更新するのが Daemonset として動いている kube-proxy。その名前からプロキシサーバーのようなものをイメージしてしまうが、実際はトラフィックを受けるわけではないので cpu: 100m ととても少ないリソースで動く。kube-proxy には iptabels 以外の mode も存在しているが今回は触れない。

iptables は パケットフィルタや NAT を行う Netfilter の設定ツール。ホストで次のコマンドを実行すると nat table の設定を確認できる。KUBE-SERVICES Chain に各 Service の ClusterIP を destination とする KUBE-SVC と、KUBE-NODEPORTS が含まれ、KUBE-NODEPORTS も KUBE-EXT を介して KUBE-SVC に繋がっている。KUBE-SVC には各 Pod の IP アドレスに DNAT する KUBE-SEP が含まれ、これが確率で選ばれることでロードバランシングされる。kube-proxy は Kubernetes API を監視し Healthy/Unhealthy な Pod のルールを追加/削除する。

$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
...

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination
KUBE-SVC-CE6JHM1SEKP18XIF  tcp  --  0.0.0.0/0            172.20.36.232        /* testapp/testapp-svc cluster IP */ tcp dpt:8080
...
KUBE-NODEPORTS  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

Chain KUBE-NODEPORTS (1 references)
target     prot opt source               destination
KUBE-EXT-W1EMVGLJN3U6KBK2  tcp  --  0.0.0.0/0            0.0.0.0/0            /* testapp/testapp2-svc */ tcp dpt:31218
...

Chain KUBE-EXT-W1EMVGLJN3U6KBK2 (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            /* masquerade traffic for testapp/testapp2-svc external destinations */
KUBE-SVC-W1EMVGLJN3U6KBK2  all  --  0.0.0.0/0            0.0.0.0/0

Chain KUBE-SVC-CE6JHM1SEKP18XIF (2 references)
target     prot opt source               destination
KUBE-SEP-F3KEHKXHH6PPCNMD  all  --  0.0.0.0/0            0.0.0.0/0            /* testapp/testapp-svc -> 10.161.33.109:8080 */ statistic mode random probability 0.01351351338
KUBE-SEP-GONI7XQNZNJEEBEO  all  --  0.0.0.0/0            0.0.0.0/0            /* testapp/testapp-svc -> 10.161.33.116:8080 */ statistic mode random probability 0.01369863003
KUBE-SEP-C2L3SYA5JOE66TCB  all  --  0.0.0.0/0            0.0.0.0/0            /* testapp/testapp-svc -> 10.161.33.129:8080 */ statistic mode random probability 0.01388888899
...

Chain KUBE-SEP-F3KEHKXHH6PPCNMD (1 references)
target     prot opt source               destination
KUBE-MARK-MASQ  all  --  10.161.33.109        0.0.0.0/0            /* testapp/testapp-svc */
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            /* testapp/testapp-svc */ tcp to:10.161.33.109:8080

参考

kube-proxy入門

ネットワークの概要 | Google Kubernetes Engine (GKE) | Google Cloud