Kubernetesのネットワーク構成

こんにちは。サイオステクノロジー技術部 武井です。以前、この記事でKubernetesを構築しました。その時、Pod宛の通信をロードバランスするClusterIPなるものがありましたが、ClusterIP宛の通信がどういう原理で、各Podにロードバランスされるかを調べてみました。また、合わせて、nodeのインターフェース宛の通信がどういう原理でPodに到達するかも調べてみました。

ネットワーク構成

Kubernetesのネットワーク構成のイメージ図は以下のとおりです。

Screen Shot 2018-02-23 at 9.01.49

上記は、この記事で構築した環境となります。以下、詳細です。

  • Pod間のネットワークはflannelというVXLANを管理するソフトウェアにより、172.30.0.0/16というネットワーク空間を持ち、さらにそのネットワークをPodごとに24ビットのネットワーク空間に区切っている。
  • flannel.1というデバイスがVXLANデバイスである。
  • 別ノード宛のパケットは、VXLANデバイスflannel.1によりVXLANヘッダが付与された形でカプセル化され、nodeのeth0を通り、別ノードに届く。(このあたりの仕組みは別記事で後述します)
  • doker0という仮想ブリッジ(IPアドレスをもっている)があり、Podはこのブリッジにつながっている。
  • Cluster IPというIPアドレスがある。ネットワークインターフェースは持たず、iptablesの中で定義された仮想的なIPアドレスである。このIPアドレス宛のパケットは各nodeにロードバランスされる。

node01のネットワーク関連の情報

この記事でServiceを作成しましたが、Serviceを作成すると、たくさんのiptablesのルールが作成されます。そのルールが複雑に絡み合い、ClusterIP宛の通信がきちんとロードバランスされる仕組みとなっています。

ここでは、node01のRouting Table、iptablesのチェイン、ネットワークインターフェースは以下のとおり記載します。以降にnode02の情報も合わせて記載しますが、これらは、通信を調査する上で重要な情報になります。これらの情報をひつつずつ分析した上で、Podにパケットがどのように届くかを調べてみたいと思います。

ネットワークインターフェース

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0d:3a:50:0f:74 brd ff:ff:ff:ff:ff:ff
    inet 10.4.4.5/24 brd 10.4.4.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::20d:3aff:fe50:f74/64 scope link 
       valid_lft forever preferred_lft forever
3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
    link/ether ea:48:c7:70:4d:6d brd ff:ff:ff:ff:ff:ff
    inet 172.30.31.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::e848:c7ff:fe70:4d6d/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:cc:c4:90:01 brd ff:ff:ff:ff:ff:ff
    inet 172.30.31.1/24 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:ccff:fec4:9001/64 scope link 
       valid_lft forever preferred_lft forever
6: vethbbd9a05@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP 
    link/ether 8a:e7:a3:a6:3c:bd brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::88e7:a3ff:fea6:3cbd/64 scope link 
       valid_lft forever preferred_lft forever

Routing Table

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    0      0        0 eth0
10.4.4.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
168.63.129.16   gateway         255.255.255.255 UGH   0      0        0 eth0
link-local      0.0.0.0         255.255.0.0     U     1002   0        0 eth0
169.254.169.254 gateway         255.255.255.255 UGH   0      0        0 eth0
172.30.0.0      0.0.0.0         255.255.0.0     U     0      0        0 flannel.1
172.30.31.0     0.0.0.0         255.255.255.0   U     0      0        0 docker0

iptablesのチェイン

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A POSTROUTING -s 172.30.31.0/24 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x40000x4000
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/dev-np:https" -m tcp --dport 31707 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/dev-np:https" -m tcp --dport 31707 -j KUBE-SVC-3UCI24FU4XAF2OPE
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
-A KUBE-SEP-2GFQOP4A6JXPIKZI -s 172.30.31.2/32 -m comment --comment "default/dev-np:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-2GFQOP4A6JXPIKZI -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.31.2:80
-A KUBE-SEP-BDZCPQIUEUTMNSCN -s 10.4.4.4/32 -m comment --comment "default/kubernetes:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-BDZCPQIUEUTMNSCN -p tcp -m comment --comment "default/kubernetes:https" -m recent --set --name KUBE-SEP-BDZCPQIUEUTMNSCN --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.4.4.4:6443
-A KUBE-SEP-OKBK5A3GPOH3UXPW -s 172.30.91.2/32 -m comment --comment "default/dev-np:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-OKBK5A3GPOH3UXPW -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.91.2:80
-A KUBE-SERVICES -d 10.254.236.167/32 -p tcp -m comment --comment "default/dev-np:https cluster IP" -m tcp --dport 80 -j KUBE-SVC-3UCI24FU4XAF2OPE
-A KUBE-SERVICES -d 10.254.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2GFQOP4A6JXPIKZI
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -j KUBE-SEP-OKBK5A3GPOH3UXPW
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https" -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-BDZCPQIUEUTMNSCN --mask 255.255.255.255 --rsource -j KUBE-SEP-BDZCPQIUEUTMNSCN
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https" -j KUBE-SEP-BDZCPQIUEUTMNSCN

node02のネットワーク関連の情報

node02のRouting Table、iptablesのチェイン、ネットワークインターフェースは以下のとおりです。

ネットワークインターフェース

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0d:3a:50:f5:1c brd ff:ff:ff:ff:ff:ff
    inet 10.4.4.7/24 brd 10.4.4.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::20d:3aff:fe50:f51c/64 scope link 
       valid_lft forever preferred_lft forever
3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN 
    link/ether 8e:21:ec:ac:11:c9 brd ff:ff:ff:ff:ff:ff
    inet 172.30.91.0/32 scope global flannel.1
       valid_lft forever preferred_lft forever
    inet6 fe80::8c21:ecff:feac:11c9/64 scope link 
       valid_lft forever preferred_lft forever
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:f8:19:58:56 brd ff:ff:ff:ff:ff:ff
    inet 172.30.91.1/24 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:f8ff:fe19:5856/64 scope link 
       valid_lft forever preferred_lft forever
6: veth8fe2e09@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP 
    link/ether d6:20:44:72:47:39 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::d420:44ff:fe72:4739/64 scope link 
       valid_lft forever preferred_lft forever

Routing Table

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         gateway         0.0.0.0         UG    0      0        0 eth0
10.4.4.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0
168.63.129.16   gateway         255.255.255.255 UGH   0      0        0 eth0
link-local      0.0.0.0         255.255.0.0     U     1002   0        0 eth0
169.254.169.254 gateway         255.255.255.255 UGH   0      0        0 eth0
172.30.0.0      0.0.0.0         255.255.0.0     U     0      0        0 flannel.1
172.30.91.0     0.0.0.0         255.255.255.0   U     0      0        0 docker0

iptablesのチェイン

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A POSTROUTING -s 172.30.91.0/24 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/dev-np:https" -m tcp --dport 31707 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/dev-np:https" -m tcp --dport 31707 -j KUBE-SVC-3UCI24FU4XAF2OPE
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
-A KUBE-SEP-2GFQOP4A6JXPIKZI -s 172.30.31.2/32 -m comment --comment "default/dev-np:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-2GFQOP4A6JXPIKZI -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.31.2:80
-A KUBE-SEP-BDZCPQIUEUTMNSCN -s 10.4.4.4/32 -m comment --comment "default/kubernetes:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-BDZCPQIUEUTMNSCN -p tcp -m comment --comment "default/kubernetes:https" -m recent --set --name KUBE-SEP-BDZCPQIUEUTMNSCN --mask 255.255.255.255 --rsource -m tcp -j DNAT --to-destination 10.4.4.4:6443
-A KUBE-SEP-OKBK5A3GPOH3UXPW -s 172.30.91.2/32 -m comment --comment "default/dev-np:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-OKBK5A3GPOH3UXPW -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.91.2:80
-A KUBE-SERVICES -d 10.254.236.167/32 -p tcp -m comment --comment "default/dev-np:https cluster IP" -m tcp --dport 80 -j KUBE-SVC-3UCI24FU4XAF2OPE
-A KUBE-SERVICES -d 10.254.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2GFQOP4A6JXPIKZI
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -j KUBE-SEP-OKBK5A3GPOH3UXPW
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https" -m recent --rcheck --seconds 10800 --reap --name KUBE-SEP-BDZCPQIUEUTMNSCN --mask 255.255.255.255 --rsource -j KUBE-SEP-BDZCPQIUEUTMNSCN
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https" -j KUBE-SEP-BDZCPQIUEUTMNSCN

ClusterIP宛の通信がPodに届くまで

ClusterIP宛の通信がPodに届くまでを調べた結果を記載します。node1のPod内のコンテナからClusterIPあて80/tcpにアクセスしたとします。


■ その1
Screen Shot 2018-02-23 at 23.31.20
Podのコンテナ内のRouting Tableにより、デフォルトゲートウェイであるdocker0のインターフェースに向かいます。


■ その2
Screen Shot 2018-02-23 at 23.31.20
Podのコンテナ内のRouting Tableにより、デフォルトゲートウェイであるdocker0のインターフェースに向かいます。


■ その3
Screen Shot 2018-02-23 at 23.47.56

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

上記のルールによりルーティングされる前にKUBE-SERVICESチェインに飛びます。

-A KUBE-SERVICES -d 10.254.236.167/32 -p tcp -m comment --comment "default/dev-np:https cluster IP" -m tcp --dport 80 -j KUBE-SVC-3UCI24FU4XAF2OPE

KUBE-SERVICESチェインにより、宛先IPアドレスがClusterIP、宛先ポートが80のパケットは、 KUBE-SVC-3UCI24FU4XAF2OPEチェインに飛びます。

-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2GFQOP4A6JXPIKZI
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -j KUBE-SEP-OKBK5A3GPOH3UXPW

KUBE-SVC-3UCI24FU4XAF2OPEチェインにより、1/2の確率でパケットはKUBE-SEP-2GFQOP4A6JXPIKZIチェインか、KUBE-SEP-OKBK5A3GPOH3UXPWチェインに飛びます。ここでは、 KUBE-SEP-OKBK5A3GPOH3UXPWチェインに飛んだとします。

-A KUBE-SEP-OKBK5A3GPOH3UXPW -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.91.2:80

KUBE-SEP-OKBK5A3GPOH3UXPWチェインにより、パケットの宛先IPアドレスは172.30.91.2、宛先ポートは80になります。


■ その4
Screen Shot 2018-02-23 at 23.54.58

172.30.0.0      0.0.0.0         255.255.0.0     U     0      0        0 flannel.

上記のRouting Tableにより、パケットはflannel.1にルーティングされます。


■ その5
Screen Shot 2018-02-23 at 23.59.18
flannel.1はVXLANデバイスなので、172.30.91.0/24宛のパケットは、宛先node02のeth0(10.4.4.7)、プロトコルUDP、ポート番号8472にカプセル化されて転送されます。この転送ルールは、Masterの中にあるetcdに記載されており、flannelがその情報をもとに、このルールを決定します。VXLANの仕組みについては別記事にて記載する予定ですので、ここでは詳細は割愛させて頂きます。

そして、

10.4.4.0        0.0.0.0         255.255.255.0   U     0      0        0 eth0

のRouting Tableにより、パケットはnode01のeth0にRoutingされます。


■ その6
Screen Shot 2018-02-24 at 0.11.34

-A POSTROUTING -s 172.30.31.0/24 ! -o docker0 -j MASQUERADE

のiptablesのルールにより、送信元は、node01のeth0(10.4.4.5)にSNATされます。


■ その7
Screen Shot 2018-02-24 at 1.23.23
node02は、受け取ったパケットがVXLANのパケットであると判断し、先程カプセル化されたL2パケットを取り出して、flannel.1に転送します。


■ その8
Screen Shot 2018-02-24 at 1.25.06

172.30.91.0     0.0.0.0         255.255.255.0   U     0      0        0 docker0

このRouting Tableによって、パケットはdocker0インタフェースに転送されます。


■ その9
Screen Shot 2018-02-24 at 1.26.49
最終的にパケットは、node02のPodに届きます。

nodeのインターフェース宛の通信がPodに届くまで

nodeのインターフェース宛の通信がPodに届くまでを調べました。


■ その1
Screen Shot 2018-02-24 at 1.37.05
node01のeth0のインターフェースの31707宛にパケットが飛んできます。


■ その2
Screen Shot 2018-02-24 at 1.38.45

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

PREROUTINGチェインは、KUBE-SERVICESチェインに飛びます。

-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS

KUBE-SERVICESでは、ローカルのインターフェース(この場合だとnodeのeth0)宛のパケットは、KUBE-NODEPORTSチェインに飛びます。

-A KUBE-NODEPORTS -p tcp -m comment --comment "default/dev-np:https" -m tcp --dport 31707 -j KUBE-SVC-3UCI24FU4XAF2OPE

KUBE-NODEPORTSチェインでは、31707/tcp宛のパケットは、KUBE-SVC-3UCI24FU4XAF2OPEチェインに飛びます。

-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2GFQOP4A6JXPIKZI
-A KUBE-SVC-3UCI24FU4XAF2OPE -m comment --comment "default/dev-np:https" -j KUBE-SEP-OKBK5A3GPOH3UXPW

KUBE-SVC-3UCI24FU4XAF2OPEチェインでは、statisticモジュールにより、50%の確率でKUBE-SEP-2GFQOP4A6JXPIKZIチェインかKUBE-SEP-OKBK5A3GPOH3UXPWチェインに飛びます。ここではKUBE-SEP-2GFQOP4A6JXPIKZIに飛んだとします。

-A KUBE-SEP-2GFQOP4A6JXPIKZI -p tcp -m comment --comment "default/dev-np:https" -m tcp -j DNAT --to-destination 172.30.31.2:80

宛先が、Pod宛のIPアドレス、ポートにNATされ、Podに転送されることがわかります。


■ その3
Screen Shot 2018-02-24 at 1.41.44

172.30.31.0     0.0.0.0         255.255.255.0   U     0      0        0 docker0

このRouting Tableにより、パケットdocker0インターフェースに届きます。


■ その4
Screen Shot 2018-02-24 at 1.42.50
最終的にパケットはPodに届きます。

最後に

いかがでしたでしょうか?iptablesのルールがたくさんあって、目が回りそうになりました。誰かのお役に立てれば幸いです。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

9人がこの投稿は役に立ったと言っています。

2 COMMENTS

アバター画像 武井宜行

ご指摘頂きまして大変ありがとうございました。早速修正させていただきました。

今後とも当社技術ブログを何卒よろしくお願い申し上げます。

返信する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です