APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【OCI】OKEから理解するKubernetesとPodの挙動について

目次

はじめに

こんにちは、クラウド事業部の照屋です。

今回はOKE及び、Kubernetesをもっと理解するために、
Podの挙動について見ていこうと思います。

どんなひとに読んで欲しい

  • Kubernetesを学習し始めた人
  • Podについて知見を深めたい人

関連記事

【OCI】OKEの疎通確認techblog.ap-com.co.jp

リソース確認

ノードプール2つ、各ノードプールにワーカーノード1台とワーカーノード2台が存在している状態です。

やりたいこと①

前提、Podは常に同じノード上で実行され続けるものではありません。Podの寿命は短命なので、削除されては再作成されるを繰り返しています。
特に設定がなければ、デフォルトとしてPodの移動範囲はクラスタ全体になります。(※ノードプールを跨いで再作成される)
ラベルセレクターを利用することで、Podが再作成される際に、どのノード上に再作成されるかを制限することができます。

まずは何も設定せずにデフォルトの挙動を確認します。
その後、ラベルセレクターで特定のノードプールに制限してみたいと思います。

事前準備

Deploymentのマニフェストファイル(YAML)を作成し、Nginxをデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/library/nginx:1.14.2
        ports:
        - containerPort: 80

挙動確認①

Podのステータスを確認します。

[opc@bation ~]$ kubectl get pods -o wide
NAME                            READY       STATUS    RESTARTS    AGE    IP             NODE        NOMINATED NODE   READINESS GATES
nginx-deployment-75b6b65ddb-tl8nh      1/1         Running    0        16h    10.0.1.107       10.0.1.30                 
nginx-deployment-75b6b65ddb-wh5bn      1/1         Running    0        16h    10.0.1.116       10.0.1.30                 

意図的にPodを削除→再作成の動きを見ていきます。
別ターミナルでPodの動きを監視します。

[opc@bation ~]$ kubectl delete pod nginx-deployment-75b6b65ddb-tl8nh
pod "nginx-deployment-75b6b65ddb-tl8nh" deleted

「nginx-deployment-75b6b65ddb-tl8nh」のNginx Podを削除しました。

Podが削除後、自動で再作成されているのが分かります。

[opc@bation ~]$ kubectl get pods -w
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-75b6b65ddb-tl8nh   1/1     Running             0          16h
nginx-deployment-75b6b65ddb-wh5bn   1/1     Running             0          16h
nginx-deployment-75b6b65ddb-tl8nh   1/1     Terminating         0          16h
nginx-deployment-75b6b65ddb-tl8nh   1/1     Terminating         0          16h
nginx-deployment-75b6b65ddb-4l6gm   0/1     Pending             0          1s
nginx-deployment-75b6b65ddb-4l6gm   0/1     Pending             0          1s
nginx-deployment-75b6b65ddb-4l6gm   0/1     ContainerCreating   0          1s
nginx-deployment-75b6b65ddb-tl8nh   0/1     Completed           0          16h
nginx-deployment-75b6b65ddb-tl8nh   0/1     Completed           0          16h
nginx-deployment-75b6b65ddb-tl8nh   0/1     Completed           0          16h
nginx-deployment-75b6b65ddb-4l6gm   1/1     Running             0          7s

Podのステータスを確認します。
10.0.1.30のワーカーノード上で実行されていたのが、
再作成後は、10.0.1.61のワーカーノード上で実行されているのが確認できます。
ノードプールを跨いで、Podがデプロイされるデフォルトの挙動を確認することができました。

[opc@bation ~]$ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
nginx-deployment-75b6b65ddb-4l6gm   1/1     Running   0          25s   10.0.1.104   10.0.1.61              
nginx-deployment-75b6b65ddb-wh5bn   1/1     Running   0          16h   10.0.1.116   10.0.1.30              

次に、ラベルセレクターでPodの移動を特定のノードプール内に制限していきます。
特定のワーカーノードに制限したい場合は、そのワーカーノードのみにラベルを付与することで実現可能です。

今回は、my-pool2というノードプールに制限してみます。
my-pool2にあるワーカーノード2台にtarget-node=web-app-01というラベルを付与します。

[opc@bation ~]$ kubectl get nodes
NAME         STATUS    ROLES    AGE       VERSION
10.0.1.30    Ready     node     3d14h     v1.34.2
10.0.1.61    Ready     node     3h47m     v1.34.2
10.0.1.96    Ready     node     3h47m     v1.34.2

[opc@bation ~]$ kubectl label nodes 10.0.1.61 target-node=web-app-01
node/10.0.1.61 labeled

[opc@bation ~]$ kubectl label nodes 10.0.1.96 target-node=web-app-01
node/10.0.1.96 labeled


ラベルが付与されていることが確認できました。

[opc@bation ~]$ kubectl get nodes --show-labels | grep target-node=web-app-01
10.0.1.61   Ready    node    3h50m   v1.34.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=VM.Standard.E5.Flex,beta.kubernetes.io/os=linux,displayName=oke-c3jths47lcq-nttaafuvupa-sbke6szcnrq-1,failure-domain.beta.kubernetes.io/region=ap-tokyo-1,failure-domain.beta.kubernetes.io/zone=AP-TOKYO-1-AD-1,hostname=oke-c3jths47lcq-nttaafuvupa-sbke6szcnrq-1,internal_addr=10.0.1.61,kubernetes.io/arch=amd64,kubernetes.io/hostname=10.0.1.61,kubernetes.io/os=linux,last-migration-failure=get_kubesvc_failure,name=my-pool2,node-role.kubernetes.io/node=,node.info.ds_proxymux_client=true,node.info/compartment.id=aaaaaaaazsmde7hqsny6dbsvnlbbqsze6jsrfxka6e3seas6xhj46im52rsq,node.info/compartment.name=test_teruya,node.info/kubeletVersion=v1.34,node.kubernetes.io/instance-type=VM.Standard.E5.Flex,oci.oraclecloud.com/fault-domain=FAULT-DOMAIN-2,oci.oraclecloud.com/host.id=493ba568f11,oci.oraclecloud.com/host.rack_id=eccc3d93c4e,oci.oraclecloud.com/ip-family-ipv4=true,oci.oraclecloud.com/ip-family-preferred=ipv4,oci.oraclecloud.com/node.info.managed=true,oci.oraclecloud.com/vcn-native-ip-cni=true,oke.oraclecloud.com/node.info.private_subnet=true,oke.oraclecloud.com/node.info.private_worker=true,target-node=web-app-01,topology.kubernetes.io/region=ap-tokyo-1,topology.kubernetes.io/zone=AP-TOKYO-1-AD-1

10.0.1.96   Ready    node    3h49m   v1.34.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=VM.Standard.E5.Flex,beta.kubernetes.io/os=linux,displayName=oke-c3jths47lcq-nttaafuvupa-sbke6szcnrq-0,failure-domain.beta.kubernetes.io/region=ap-tokyo-1,failure-domain.beta.kubernetes.io/zone=AP-TOKYO-1-AD-1,hostname=oke-c3jths47lcq-nttaafuvupa-sbke6szcnrq-0,internal_addr=10.0.1.96,kubernetes.io/arch=amd64,kubernetes.io/hostname=10.0.1.96,kubernetes.io/os=linux,last-migration-failure=get_kubesvc_failure,name=my-pool2,node-role.kubernetes.io/node=,node.info.ds_proxymux_client=true,node.info/compartment.id=aaaaaaaazsmde7hqsny6dbsvnlbbqsze6jsrfxka6e3seas6xhj46im52rsq,node.info/compartment.name=test_teruya,node.info/kubeletVersion=v1.34,node.kubernetes.io/instance-type=VM.Standard.E5.Flex,oci.oraclecloud.com/fault-domain=FAULT-DOMAIN-1,oci.oraclecloud.com/host.id=c9e3e9e733c,oci.oraclecloud.com/host.rack_id=112ecddc753,oci.oraclecloud.com/ip-family-ipv4=true,oci.oraclecloud.com/ip-family-preferred=ipv4,oci.oraclecloud.com/node.info.managed=true,oci.oraclecloud.com/vcn-native-ip-cni=true,oke.oraclecloud.com/node.info.private_subnet=true,oke.oraclecloud.com/node.info.private_worker=true,target-node=web-app-01,topology.kubernetes.io/region=ap-tokyo-1,topology.kubernetes.io/zone=AP-TOKYO-1-AD-1

マニフェストファイル(YAML)に、nodeSelector:を追加します。


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/library/nginx:1.14.2
        ports:
        - containerPort: 80

      nodeSelector:
        target-node: web-app-01

更新かけます。

[opc@bation ~]$ kubectl apply -f pod.yaml
deployment.apps/nginx-deployment configured

Podのステータスを確認します。
my-pool2にあるワーカーノードにPodが存在していることが確認できます。

[opc@bation ~]$ kubectl get pods -o wide
NAME                              READY     STATUS    RESTARTS   AGE    IP           NODE        NOMINATED NODE   READINESS GATES
nginx-deployment-55487c76b9-cnq4l   1/1      Running   0           12s    10.0.1.159     10.0.1.96                  
nginx-deployment-55487c76b9-jr5wn   1/1      Running   0           5s     10.0.1.136     10.0.1.61                  

削除→再作成後もmy-pool1のワーカーノードに移動することはないか確認してみます。

[opc@bation ~]$ kubectl delete pod nginx-deployment-55487c76b9-cnq4l
pod "nginx-deployment-55487c76b9-cnq4l" deleted
[opc@bation ~]$
[opc@bation ~]$ kubectl get pods -o wide
NAME                                READY     STATUS    RESTARTS   AGE      IP            NODE        NOMINATED NODE   READINESS GATES
nginx-deployment-55487c76b9-ghls9   1/1       Running   0          6s        10.0.1.201   10.0.1.96                         
nginx-deployment-55487c76b9-jr5wn   1/1       Running   0          7m6s      10.0.1.136   10.0.1.61                         
[opc@bation ~]$
[opc@bation ~]$ kubectl delete pod nginx-deployment-55487c76b9-jr5wn
pod "nginx-deployment-55487c76b9-jr5wn" deleted
[opc@bation ~]$
[opc@bation ~]$ kubectl get pods -o wide
NAME                                READY     STATUS    RESTARTS   AGE      IP            NODE        NOMINATED NODE   READINESS GATES
nginx-deployment-55487c76b9-68bs6   1/1       Running   0          4s        10.0.1.73    10.0.1.61                         
nginx-deployment-55487c76b9-ghls9   1/1       Running   0          36s       10.0.1.201   10.0.1.96                         

my-pool2内でのみ移動するだけで、ノードプールを跨いだ移動は確認できませんでした。(Podの移動がmy-pool2ノードプール内に制限されてそうです…!)

参考

ラベルセレクター

やりたいこと②

クライアント(VM)からFLBを経由してPodにアクセスする場合、
1. FLB → ワーカーノード
2. ワーカーノード → Pod
二段階で通信が転送されていきます。これがデフォルトの通信経路になります。

OKEでは、FLBのバックエンドとしてワーカーノードではなく、Podを指定することで、
ワーカーノードを完全にバイパスし、直接PodのIPアドレスに転送するように設定することができます。
通信経路としては、クライアント(VM)→FLB→Pod(直接Podに届く)になります。

FLBのバックエンドをPodにするメリット

ネットワーク効率の向上
中間ノードでのルーティングを排除することで、ネットワークの輻輳とオーバーヘッドが削減されます。
最適化されたリソース使用率
正常なポッドのみがバックエンドとして登録されるため、バックエンドの管理が簡素化され、スケーラビリティが向上する可能性があります。
よりシンプルなヘルスチェック
ロード バランサは各アプリケーションポッドを直接プローブするため、ヘルスモニタリングの精度が向上します。
ノードの負荷軽減
ノードからトラフィックをオフロードすると、処理の負担が軽減され、アプリケーションのパフォーマンスがより予測可能になります。

バックエンドとしてポッドを使用するための前提条件

  1. OKEクラスタの Kubernetes バージョンは1.30 以降であること
  2. クラスタ作成時に、ネットワーク・タイプとして「VCNネイティブ・ポッド・ネットワーク」を選択していること

事前準備②

  1. OKEクラスタの Kubernetes バージョンは1.30 以降であること

→クラスタ本体のバージョンを確認します。

[opc@bation ~]$ kubectl version
Client Version: v1.33.7+1.el9
Kustomize Version: v5.6.0
Server Version: v1.34.2

Server Version: v1.34.2なので、条件を満たしていることが確認できました。

  1. クラスタ作成時に、ネットワーク・タイプとして「VCNネイティブ・ポッド・ネットワーク」を選択していること

→OKEクラスタ構築時に「VCNネイティブ・ポッド・ネットワーク」で作成している前提で進めます。

FLBを経由してPodにアクセスするため、ロードバランサを作成しておきます。
ここで、アプリをデプロイするために作成したDeploymentのマニフェストファイル(YAML)に、
type: LoadBalancerを追記してしまうとエラーになってしまいます。

なぜか?
→アプリをデプロイする用のマニフェストファイル(Deployment)と
 通信を制御する用のマニフェストファイル(Service)があるからです。

type: LoadBalancerは、Serviceに書く必要があります。


apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:

  type: LoadBalancer

  selector:
    app: nginx
  ports:
    - name: http
      port: 80
      targetPort: 80

Serviceを適用していきます。

[opc@bation ~]$ kubectl apply -f nginx-service.yaml
service/nginx-service created

[opc@bation ~]$ kubectl get svc -w
NAME              TYPE            CLUSTER-IP      EXTERNAL-IP     PORT(S)                AGE
kubernetes        ClusterIP        10.96.0.1                      443/TCP,12250/TCP         3d22h
nginx-service     LoadBalancer      10.96.200.18                      80:32627/TCP              12s

nginx-service      LoadBalancer     10.96.200.18    161.33.214.206    80:32627/TCP              19s

コンソール画面からロードバランサが作成されていることが確認できました。

事前知識

デフォルトの動きを確認していく前に、
externalTrafficPolicyとは何か?について触れておこうと思います。

externalTrafficPolicyには、 Cluster(デフォルト)と、Localという値が設定できます。
※明示的に指定しない(省略する)場合、デフォルト値であるClusterが適用されます。

externalTrafficPolicy: Clusterの場合、 FLBからの通信がどのワーカーノードに届いても、全ワーカーノードのPodへ転送できます。
但し、送信元IPアドレスは保持されないため、Podに届く通信の送信元IPは、クライアントのIPではなく、ワーカーノードのプライベートIPになります。

externalTrafficPolicy: Localの場合、 FLBからの通信がワーカーノードAに届いた場合、ワーカーノードA上で動いているPodにのみ通信は渡されます。
この時、送信元IPアドレスは保持されるため、Podに届く通信の送信元IPは、クライアントのIPになります。
※今回はFLBを経由するため、FLBがバックエンドのアクセスに使用するバックエンドIPになるはずです。

参考

KubernetesのServiceのexternalTrafficPolicyとinternalTrafficPolicyって何?

挙動確認②

デフォルトの動きについて確認していきます。
まず、VM(Bastionサーバ)からFLBに向けてcurlコマンドを投げます。


[opc@bation ~]$ curl -I http://161.33.214.206
HTTP/1.1 200 OK
Server: nginx/1.14.2

Date: Thu, 12 Feb 2026 05:43:47 GMT

Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: ***********
Accept-Ranges: *****

200が返ってきたので、通信はPodまで到達できていることが確認できます。

では、通信が本当に「デフォルト経路」で到達したかを確認したいと思います。
externalTrafficPolicy: Cluster

Pod名を確認します。

[opc@bation ~]$ kubectl get pods -o wide
NAME                                  READY     STATUS    RESTARTS     AGE    IP            NODE         NOMINATED NODE   READINESS GATES
nginx-deployment-55487c76b9-68bs6    1/1      Running   2            46h   10.0.1.104     10.0.1.61           
nginx-deployment-55487c76b9-ghls9    1/1      Running   2             46h   10.0.1.159     10.0.1.96           

ワーカーノードA(10.0.1.61)にいるPod が nginx-deployment-55487c76b9-68bs6
ワーカーノードB(10.0.1.96)にいるPod が nginx-deployment-55487c76b9-ghls9


[opc@bation ~]$ kubectl logs nginx-deployment-55487c76b9-68bs6
10.0.1.96 - - [12/Feb/2026:05:29:53 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 zgrab/0.x" "-"
10.0.1.61 - - [12/Feb/2026:05:33:13 +0000] "\x16\x03\x02\x01o\x01\x00\x01k\x03\x02RH\xC5\x1A#\xF7:N\xDF\xE2\xB4\x82/\xFF\x09T\x9F\xA7\xC4y\xB0h\xC6\x13\x8C\xA4\x1C=\x22\xE1\x1A\x98 \x84\xB4,\x85\xAFn\xE3Y\xBBbhl\xFF(=':\xA9\x82\xD9o\xC8\xA2\xD7\x93\x98\xB4\xEF\x80\xE5\xB9\x90\x00(\xC0" 400 173 "-" "-" "-"
2026/02/12 05:42:45 [error] 6#6: *3 open() "/usr/share/nginx/html/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php" failed (2: No such file or directory), client: 10.0.1.30, server: localhost, request: "POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1", host: "161.33.214.206:80"
10.0.1.30 - - [12/Feb/2026:05:42:45 +0000] "POST /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" "-"

10.0.1.96 - - [12/Feb/2026:05:43:47 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.76.1" "-"

10.0.1.96 - - [12/Feb/2026:05:51:32 +0000] "POST / HTTP/1.1" 405 173 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" "-"

10.0.1.61上にあるPodのログを見ると、送信元IPが10.0.1.96になっており、ワーカーノードBから通信が届いています。

つまり、先ほどのクライアントからの通信は、FLBを経由して、ワーカーノードBに到達し、ワーカーノードBからワーカーノードA上にあるPodに転送されたことが分かります。(externalTrafficPolicy: Clusterの挙動が確認できましたね!)

本稿の趣旨から少し脱線してしまいますが、
ついでにexternalTrafficPolicy: Localに設定した場合の挙動も見ておきたいと思います。

Service(nginx-service.yaml)を下記の通りに書き替えます。


apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: LoadBalancer

  externalTrafficPolicy: Local

  selector:
    app: nginx
  ports:
    - name: http
      port: 80
      targetPort: 80

変更を適用します。

[opc@bation ~]$ kubectl apply -f nginx-service.yaml
service/nginx-service configured

もう一度curlを投げて、200が返ってくることを確認します。


[opc@bation ~]$ curl -I http://161.33.214.206
HTTP/1.1 200 OK
Server: nginx/1.14.2

Date: Thu, 12 Feb 2026 06:40:38 GMT

Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes

ワーカーノードAのPodのログを確認していきます。


[opc@bation ~]$ kubectl logs nginx-deployment-55487c76b9-68bs6
10.0.1.61 - - [12/Feb/2026:06:10:50 +0000] "GET /security.txt HTTP/1.1" 404 169 "-" "Mozilla/5.0 (compatible; CensysInspect/1.1; +https://about.censys.io/)" "-"
10.0.1.96 - - [12/Feb/2026:06:23:30 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"

10.0.2.64 - - [12/Feb/2026:06:40:38 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.76.1" "-"

ロードバランサがあるサブネットのCIDR(10.0.2.0/24)から割り当てられたバックエンドIPが、送信元IPになっていることが確認できます。

一通りの挙動が確認できたところで、
最後に、バックエンドとしてPodを指定し、クライアント(VM)から直接Podに通信が届くのかを確認していきます。

事前準備③

Kubernetesエンジンは、oci-cloud-controller-manager (CCM)を使用して、Kubernetes サービス用のロードバランサをプロビジョニングします。
oci-cloud-controller-manager (CCM)がNSGを自動管理できるように、必要なIAM ポリシーを付与しておきます。

ALLOW any-user to manage network-security-groups in compartment <compartment-name> where request.principal.type = 'cluster'

※制御方法としては、NSGとセキュリティ・リストがありますが、
今回はOracleの推奨であるNSGで設定していきます。

参考

ロードバランサーとネットワークロードバランサーのセキュリティルール管理オプションの指定


次に、Serviceにoci.oraclecloud.com/security-rule-management-mode: "NSG"の追加と、管理対象のNSGのOCIDを記述します。
ここで設定するNSGはPod用のNSGになります。

ワーカーノードには、プライマリVNICとセカンダリVNICがあります。
プライマリVNICにアタッチされているNSGでワーカーノード側を制御し、セカンダリVNICにアタッチされているNSGでPod側を制御できるようになっています。

ServiceにNSGを記述しておくことで、CCMが対象のNSGに対して自動でルールの追加や削除を行えるようになりますので、
NSGを新規作成するだけで、中身のルールは手動で追加する必要がありません。

※FLB用のNSGについては、自動でNSGを新規作成のうえ必要なルールを追加して、FLBにアタッチまでしてくれます。

挙動確認③

OCI公式ドキュメントを参考にしながら、Serviceのマニフェストファイルを下記の通りに書き換えていきます。

現在はまだバックエンドがワーカーノードになっていますが、 ServiceのマニフェストファイルにallocateLoadBalancerNodePorts: falseを含めることで、NodePortの割り当てを無効にします。
=「1. FLB → ワーカーノード」の経路自体を作らないように設定します。
oci.oraclecloud.com/load-balancer-backend-set-type: "IP"を記述することで、バックエンドをPodに設定することができるようになります。


apiVersion: v1
kind: Service
metadata:
  name: nginx-service

  annotations:
    oci.oraclecloud.com/load-balancer-backend-set-type: "IP"
    oci.oraclecloud.com/load-balancer-type: "lb"
    oci-load-balancer.oraclecloud.com/health-check: '{"protocol": "HTTP", "port": 80, "urlPath": "/", "returnCode": 200, "retries": 3, "timeoutInMillis": 3000}'
    oci.oraclecloud.com/security-rule-management-mode: "NSG"
    oci.oraclecloud.com/oci-backend-network-security-group: "<nsg-ocid>"

spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
    - name: http
      port: 80
      targetPort: 80

  allocateLoadBalancerNodePorts: false

変更を適用させるために一度Serviceを削除して再作成します。

[opc@bation ~]$ kubectl delete svc nginx-service
service "nginx-service" deleted

↓ ロードバランサが削除されていることを確認します。

[opc@bation ~]$ kubectl apply -f nginx-service.yaml
service/nginx-service created

curlを投げて、結果を確認していきます。


[opc@bation ~]$ curl -I http://132.226.7.70
HTTP/1.1 200 OK
Server: nginx/1.14.2

Date: Sun, 15 Feb 2026 15:34:36 GMT

Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes

送信元IPを確認するために、Podのログも確認していきます。


[opc@bation ~]$ kubectl logs nginx-deployment-75b6b65ddb-fh4lm
10.0.2.140 - - [15/Feb/2026:15:34:27 +0000] "GET / HTTP/1.1" 200 612 "-" "-" "-"
10.0.2.140 - - [15/Feb/2026:15:34:28 +0000] "GET / HTTP/1.1" 200 612 "-" "-" "-"

10.0.2.140 - - [15/Feb/2026:15:34:36 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.76.1" "-"

10.0.2.140 - - [15/Feb/2026:15:34:37 +0000] "GET / HTTP/1.1" 200 612 "-" "-" "-"

送信元IPとして、ロードバランサーサブネットのCIDR(10.0.2.0/24)から割り当てられたバックエンドIPを確認できました!
が、ちょっと気になるのは、この通信は本当にNodePort(ワーカーノード)を通っていないのか?という点です。

ワーカーノードサブネットとPodサブネットを分けている場合は、バックエンド・セットの詳細画面にて、バックエンドのIPアドレスがワーカーノードからPodに変わっているので問題ないと思いますが、
同じサブネットにしていた場合は、ログの結果だけでは、externalTrafficPolicy: Localに設定したときとの違いが分からないですね。
ということで、FLB→Podに直接通信が届いているのかを確認するために、ワーカーノード用のNSGと、ワーカーノードサブネットにアタッチされているセキュリティリストのすべてのルールを削除してみたいと思います。

■NSG

■セキュリティリスト

Serviceを再適用してロードバランサを作成していきます。

問題なく通信できていることが確認できました!
これにより、FLB→Podに直接通信が届いていることが証明できたかと思います。

[opc@bation ~]$ curl -I http://138.2.23.218
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Sun, 15 Feb 2026 15:51:46 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes

参考

バックエンドとしてポッドを指定する

LoadBalancer タイプ

おわりに

今回はPodの挙動に焦点を当てましたが、
Kubernetesは奥が深いので、また気になることがあった際は検証しようと思います。

お知らせ

私達クラウド事業部はクラウド技術を活用したSI/SESのご支援をしております。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp