LinuCエヴァンジェリスト・Open Source Summit Japan 2022ボランティアリーダーの鯨井貴博@opensourcetechです。
はじめに
今回は、kubernetes環境における送信元IPアドレスの保持について確認してみます。
以下の記事にあるService(LoadBalancer)環境を使って確認していきます。
https://www.opensourcetech.tokyo/entry/20230316/1678966960
試験環境の構築
まず、試験用の環境構築。
namespace(名前空間)の作成。
kubeuser@master01:~/20231008$ cat ns.yaml apiVersion: v1 kind: Namespace metadata: name: seminar kubeuser@master01:~/20231008$ kubectl apply -f ns.yaml namespace/seminar created kubeuser@master01:~/20231008$ kubectl get ns | grep seminar seminar Active 15s
Webサーバ用のconfigmap・Deploymentの作成。
kubeuser@master01:~/20231008$ cat configmap_html.yaml apiVersion: v1 data: index.html: | <!DOCTYPE html> <html> <head> <title>20231008 k8sセミナー</title> <style> html { color-scheme: dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Thnak you for joining today's seminer!</h1> </body> </html> kind: ConfigMap metadata: name: indexhtml namespace: seminar kubeuser@master01:~/20231008$ kubectl apply -f configmap_html.yaml configmap/indexhtml created kubeuser@master01:~/20231008$ kubectl get cm -n seminar NAME DATA AGE indexhtml 1 6s kube-root-ca.crt 1 71s kubeuser@master01:~/20231008$ cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: webserver name: webserver namespace: seminar spec: replicas: 2 selector: matchLabels: app: webserver strategy: {} template: metadata: labels: app: webserver spec: containers: - image: nginx:latest name: nginx volumeMounts: - name: index-volume mountPath: /usr/share/nginx/html volumes: - name: index-volume configMap: name: indexhtml kubeuser@master01:~/20231008$ kubectl apply -f deployment.yaml deployment.apps/webserver created kubeuser@master01:~/20231008$ kubectl get deployments.apps -n seminar NAME READY UP-TO-DATE AVAILABLE AGE webserver 2/2 2 2 27s kubeuser@master01:~/20231008$ kubectl get pods -n seminar NAME READY STATUS RESTARTS AGE webserver-68c554c9f6-ck6h2 1/1 Running 0 30s webserver-68c554c9f6-nlhk2 1/1 Running 0 30s kubeuser@master01:~/20231008$ kubectl get pods -n seminar -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES webserver-68c554c9f6-ck6h2 1/1 Running 0 8m31s 10.0.30.88 worker02 <none> <none> webserver-68c554c9f6-nlhk2 1/1 Running 0 8m31s 10.0.5.8 worker01 <none> <none>
Serviceの作成。
kubeuser@master01:~/20231008$ cat service.yaml apiVersion: v1 kind: Service metadata: labels: app: webserver name: webserver namespace: seminar spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: webserver externalTrafficPolicy: Cluster type: LoadBalancer kubeuser@master01:~/20231008$ kubectl apply -f service.yaml service/webserver created kubeuser@master01:~/20231008$ kubectl get svc -n seminar NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE webserver LoadBalancer 10.1.246.94 192.168.1.56 80:32305/TCP 7s
デフォルト値(externalTrafficPolicy: Cluster)の場合
では、この状態でClientからの送信元IPアドレスがPodから見るとどのようになるか確認します。
確認には、sternを使います。
Serviceで公開されたIPアドレス(192.168.1.56)&ポート番号(TCP80)にアクセスすると、
送信元はNode(worker01、192.168.1.45)になっています。
kubeuser@master01:~/20231008$ kubectl get pods -n seminar NAME READY STATUS RESTARTS AGE webserver-68c554c9f6-ck6h2 1/1 Running 0 3m17s webserver-68c554c9f6-nlhk2 1/1 Running 0 3m17s kubeuser@master01:~/20231008$ stern webserver-68c554c9f6 -n seminar + webserver-68c554c9f6-ck6h2 › nginx + webserver-68c554c9f6-nlhk2 › nginx . . . . webserver-68c554c9f6-ck6h2 nginx 10.0.5.0 - - [15/Oct/2023:04:23:57 +0000] "GET / HTTP/1.1" 200 292 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-" webserver-68c554c9f6-ck6h2 nginx 2023/10/15 04:23:57 [error] 29#29: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 10.0.5.0, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.1.56", referrer: "http://192.168.1.56/" webserver-68c554c9f6-ck6h2 nginx 10.0.5.0 - - [15/Oct/2023:04:23:57 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "http://192.168.1.56/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-" webserver-68c554c9f6-nlhk2 nginx 192.168.1.45 - - [15/Oct/2023:04:23:58 +0000] "GET / HTTP/1.1" 200 292 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-" webserver-68c554c9f6-nlhk2 nginx 2023/10/15 04:23:58 [error] 29#29: *2 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.1.45, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.1.56", referrer: "http://192.168.1.56/" webserver-68c554c9f6-nlhk2 nginx 192.168.1.45 - - [15/Oct/2023:04:23:58 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "http://192.168.1.56/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-"
kubeuser@master01:~/20231008$ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master01 Ready control-plane 214d v1.27.0 192.168.1.41 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18 worker01 Ready <none> 214d v1.27.0 192.168.1.45 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18 worker02 Ready <none> 214d v1.27.0 192.168.1.46 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18
これはexternalTrafficPolicy:がCluster(デフォルト値)となっているためで、
ClientのIPアドレス -----> Service -----> Node(worker01) でSNAT(送信元IPNAT)---> Pod という動作をしているからです。
つまり、ClientのIPアドレスは不明ということです。
externalTrafficPolicy: Localの場合
では、externalTrafficPolicyをLocalとして動作を見てみましょう。
externalTrafficPolicy: LocalとServiceの設定を変更します。
kubeuser@master01:~/20231008$ cat service.yaml apiVersion: v1 kind: Service metadata: labels: app: webserver name: webserver namespace: seminar spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: webserver externalTrafficPolicy: Local type: LoadBalancer kubeuser@master01:~/20231008$ kubectl apply -f service.yaml service/webserver configured
改めてクライアントからアクセスすると、
送信元IP(192.168.1.122)が表示されています。
kubeuser@master01:~/20231008$ stern webserver-68c554c9f6 -n seminar + webserver-68c554c9f6-ck6h2 › nginx + webserver-68c554c9f6-nlhk2 › nginx . . . . . webserver-68c554c9f6-nlhk2 nginx 192.168.1.122 - - [15/Oct/2023:04:29:41 +0000] "GET / HTTP/1.1" 200 292 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-" webserver-68c554c9f6-nlhk2 nginx 192.168.1.122 - - [15/Oct/2023:04:29:41 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "http://192.168.1.56/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0" "-" webserver-68c554c9f6-nlhk2 nginx 2023/10/15 04:29:41 [error] 30#30: *3 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.1.122, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.1.56", referrer: "http://192.168.1.56/"
externalTrafficPolicyについて
externalTrafficPolicyをLocalに設定した場合の動作ですが、
・ノードに到達したリクエスト通信が他のノードに転送されなくなる
・クライアントの送信元IPアドレスを保持する(SNATされない)
というようになります。
なお、公式ドキュメントでは以下に記載があります。
https://kubernetes.io/docs/tutorials/services/source-ip/
https://kubernetes.io/ja/docs/tutorials/services/source-ip/
おわりに
externalTrafficPolicy: Localを使うことでPodログにてクライアントの送信元IPアドレスが確認出来る事が分かりました。
これを利用する上では本家ドキュメントにあるような留意点や、
kubernetes環境における通信を制御するkube-proxyなども併せて深堀する必要がありそうです。
kube-proxyのmodeをiptablesからipvsに変更する