Kubernetes の Service (Cluster IP) がどう実装されてるか
まぁ 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 の実体ともいえるものっぽい。
iptables
の statistic
という 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 */
めでたしめでたし。
Discussion
Service を実現しているコンポーネントは kube-proxy なのですが、kube-proxy には userspace (古い)、iptables(デフォルト)、ipvs の3つのモードがあるので、一概に iptables でできているとは言えないのです。ただ知る限りほとんどのクラスタでは iptables モードが選択されています。
近頃は kube-proxy を使わずに CNI プラグインがその役割も持っているものもあり、Calico や Cilium がサポートしています。使われているという話はあまり聞かないです。
typo されてますねw
おおおーーーーコメントありがとうございます。
kube-proxy の役割についてももう少し読んでみるようにします!
いやー e を何個書けばいいかわからくなっちゃうんですよねw 直しておきました!