Kubernetesのネットワーク構成

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

こんにちは。サイオステクノロジー技術部 武井です。以前、この記事で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のルールがたくさんあって、目が回りそうになりました。誰かのお役に立てれば幸いです。

アバター画像
About 武井 宜行 269 Articles
Microsoft MVP for Azure🌟「最新の技術を楽しくわかりやすく」をモットーにブログtech-lab.sios.jp)で情報を発信🎤得意分野はAzureによるクラウドネイティブな開発(Javaなど)💻「世界一わかりみの深いクラウドネイティブ on Azure」の動画を配信中📹 https://t.co/OMaJYb3pRN
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

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

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


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

2 Comments

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

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

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる