🍣

ざっくりとKubernetesの通信について探る

2022/05/19に公開

はじめに

業務で必要になってくるので最近ようやくKubernetesについてキャッチアップしています。今回はKubernetesのワーカーノード周りの通信がどのように行われているかを探ってみたかったのでGKEを用いて確認していきます。ワーカーノードをじっくり触っていくため、クラスタモードはGKE Standardの一般公開クラスタを使います。クラスタは作成済み&ローカルで接続済みの状況を想定として話を進めていきたいと思います。

Google Kubernetes Engineのアーキテクチャ

gke.png

通信を確認するために作ったもの

GolangでAPI Serverを作成しました。HTTPリクエストするとIPアドレスを返してくれるものです。これでどのように通信が行われているかを確認していきたいと思います。

main.go
package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		interfaces, err := net.Interfaces()
		if err != nil {
			fmt.Println(err)
			return
		}
		for _, inter := range interfaces {
			addrs, err := inter.Addrs()
			if err != nil {
				fmt.Println(err)
				return
			}
			for _, a := range addrs {
				if ipnet, ok := a.(*net.IPNet); ok {
					if ipnet.IP.To4() != nil {
						fmt.Fprintf(w, ipnet.IP.String() + "\n")
					}
				}
			}
		}
	})
	log.Fatal(http.ListenAndServe(":8080", nil))
}

コンテナのデプロイ

deploymentを作成します。

kubectl create deployment go-app --image=asia-northeast1-docker.pkg.dev/${projectId}/go-repo/go-app:latest

Podを3つに増やします。

kubectl scale deployment --replicas 3 go-app

NodeとPodの関係

以下のコマンドを実行してnodeの詳細を確認します。

kubectl get node -o wide

nodeが3台起動していることを確認できます。
スクリーンショット 2022-05-19 14.41.51.png

以下のコマンドを実行してpodの詳細を確認します。

kubectl get pod -o wide

podが3台起動していることを確認できます。しかし、3台のワーカーノードに1つずつPodが起動しているようではないみたいです。
スクリーンショット 2022-05-19 14.42.27.png

図にすると以下のような関係になっています。ワーカーノードにPodが1つずつ配置されるというわけではないみたいです。

k8s (1).png

Serviceの作成(L4ロードバランサの設置)

Serviceの80番ポートにアクセスするとpodの8080番ポートに転送します

kubectl expose deployment go-app --type=LoadBalancer --port 80 --target-port 8080

以下のコマンドでServiceを確認することができます。

kubectl get svc -o wide

ワーカーノードの32192番ポートにアクセスすればCLUSTER-IPに転送するようになりました。
スクリーンショット 2022-05-19 14.52.51.png

L7ロードバランサにHTTPリクエスト

curl http://35.200.9.207

こんな感じで各ノードにランダムで通信が行われていることがわかります。
スクリーンショット 2022-05-19 14.55.26.png

ワーカーノードにHTTPリクエスト

今回はGKEを一般公開クラスタとしているので各ワーカーノードにPublicIPアドレスが割り当てられています。各ノードのファイヤーウォールのルールに32192番ポートの通信を許可し、各ノードに対してHTTPリクエストを行います。

curl 34.146.102.39:32192
curl 34.85.123.215:32192
curl 34.85.115.12:32192

結果は以下のようになりました。
スクリーンショット 2022-05-19 15.05.05.png

図にまとめると以下のような感じです。 アクセスするワーカーノード上にPodがなかったとしても問題なく別のワーカーノードに対してパケットが振り分けられている。
k8s (2).png

クラスタ内から直接PodにHTTPリクエスト

クラスタ内にubuntuのPodを立て、そこからHTTPリクエストを行います。

kubectl run -it ubuntu --image=ubuntu bash

curlコマンドのインストール

apt-get update
apt-get install curl -y

試しにCLUSTER-IPにHTTPリクエストを行います。

curl http://10.56.11.169

結果は以下のようになりました。ちゃんと各Podに振り分けられていますね。
スクリーンショット 2022-05-19 23.23.46.png

本命の各Podに直接HTTPリクエストを行います。

curl http://10.52.2.5:8080
curl http://10.52.2.6:8080
curl http://10.52.1.4:8080

結果は以下のようになりました。こちらもちゃんと各Podに振り分けられていますね。
スクリーンショット 2022-05-19 23.26.56.png

どうやってPodに通信しているのか

各ワーカーノードに存在するkube-proxyがアクセスを振り分けているように見えるが、実際はapiserverの変更を検知してiptablesのDNATルールを追加、変更、削除を行うだけであり、アクセスの振り分けはiptablesというOS側の仕組みで実行する。CLUSTER-IPの実態はiptablesとなっている。

以下のようにiptables上のチェインを処理しています。
image.png
Ref: https://www.atmarkit.co.jp/ait/articles/1002/09/news119.html

ここからはiptablesどのようになっているかざっくり見ていきます。PREROUTINGチェインのKUBE-SERVICESを見ていきます

kubectl exec -it Pod名(kube-proxyなんとか) -n kube-system -- iptables -t nat -nL KUBE-SERVICES

CLUSTER-IPを発見した。
スクリーンショット 2022-05-19 20.28.31.png

KUBE-SVC-7WFRCR3BAURI7IH5を見ていきます。

kubectl exec -it Pod名(kube-proxyなんとか) -n kube-system -- iptables -t nat -nL KUBE-SVC-7WFRCR3BAURI7IH5

iptablesでは、ルールは上から下に順番に一致します。1番目のルールがヒットする確率が33%、2番目のルールがヒットする確率が50%、3番目は必ずヒットするので3つのルールに当たる確率は同じであることがわかります。
スクリーンショット 2022-05-19 20.26.34.png

KUBE-SEP-WWRWIUIMT3RFPW3Fを見ていきます。

kubectl exec -it Pod名(kube-proxyなんとか) -n kube-system -- iptables -t nat -nL KUBE-SEP-WWRWIUIMT3RFPW3F 

10.52.1.4:8080(Pod)にDNATされることが確認できました。
スクリーンショット 2022-05-19 20.31.34.png

ざっくりとiptablesについて探りました。ここから先の内容は以下の記事がとても参考になりますよ。

https://qiita.com/sugimount/items/d0f5232b983e1deac556

参考文献

https://kubernetes.io/ja/docs/concepts/services-networking/service/

https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview?hl=ja

https://recruit.gmo.jp/engineer/jisedai/blog/kubernetes_service/

https://christina04.hatenablog.com/entry/iptables-outline

https://blog.vpantry.net/2020/07/k8s-7/

https://qiita.com/inductor/items/c5bf93bc9d9c4081a1fc

https://qiita.com/sugimount/items/d0f5232b983e1deac556

https://zenn.dev/ryusa/articles/3000-lines-in-search-of-service

Discussion