LoginSignup
1
0

More than 1 year has passed since last update.

OpenShiftでService Internal Traffic Policyを試してみる

Last updated at Posted at 2022-12-05

この記事について

Kubernetesのベータ版機能としてService Internal Traffic Policyが提供されています。
この機能がOpenShift環境でも使えるかどうか確認してみました。

Service Internal Traffic Policyについて

ドキュメント

どんな機能か

クラスター内のPod間通信をローカルに制御する機能です。
とあるPodからService経由で別のPodにリクエストを投げる際、発信元と同ノードにスケジュールされているPodにのみリクエストを割り振ってくれます。

具体例を挙げると、下記図について、podからappのServiceに対してリクエストを投げると、podのあるノード1上のapp podへアクセスすることになります。
policy.drawio.png

設定方法

上記例で言うと、app podのServiceにspec.internalTrafficPolicy: Localに設定すればOK。

検証内容と結論

ざっくり検証内容

  1. アクセスするとホスト名を返すFlaskアプリを作成し、コンテナーイメージ化
  2. そのコンテナーイメージをOpenShiftにデプロイ
  3. アプリのServiceにspec.internalTrafficPolicy: Localを設定する
  4. 別Podからアプリにアクセスしてみる

結論

同ノードにアプリのPodがあればそのPodにのみリクエストが割り振られる。ない場合はどこにもリクエストは割り振らない。

検証

環境

Red Hat OpenShift on IBM Cloud上で検証。

$ oc version
Client Version: 4.10.0-202208301216.p0.gdd2bcd0.assembly.stream-dd2bcd0
Server Version: 4.11.12
Kubernetes Version: v1.24.6+5157800

ノードは4つで構成。

$ oc get node
NAME          STATUS   ROLES           AGE   VERSION
10.245.0.11   Ready    master,worker   13d   v1.24.6+5157800
10.245.0.12   Ready    master,worker   13d   v1.24.6+5157800
10.245.64.7   Ready    master,worker   13d   v1.24.6+5157800
10.245.64.8   Ready    master,worker   13d   v1.24.6+5157800

検証手順

アプリ作成

$ ls
Dockerfile  app.py
app.py
from flask import Flask
import socket

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello world from {}</p>".format(socket.gethostname())

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080, debug=True)
Dockerfile
FROM python:3.6-alpine

RUN pip install flask

COPY app.py /opt/

EXPOSE 8080

WORKDIR /opt

ENTRYPOINT ["python", "app.py"]

上記Dockerfileとアプリケーションでイメージビルドします。

$ podman build -t print-hostname .

IBM Cloud Container Registry(ICR)にイメージを保管して、そこからOpenShiftにデプロイしたいので、まずイメージのタグ付けをします(事前にレジストリーの名前空間は作成済)。

$ podman tag localhost/print-hostname:latest jp.icr.io/mynamespace/print-hostname:latest

IBM Cloudにログインした状態で、ICRのリージョンをセット。

$ ibmcloud cr region-set jp-tok

その状態でICRの認証。

$ ibmcloud cr login --client podman

認証出来たらレジストリーにプッシュ。

$ podman push jp.icr.io/mynamespace/print-hostname

OpenShiftにアプリデプロイ

ICRからイメージプルするため、あらかじめ作成したProjectにイメージプルシークレットを作成します。

$ oc get secret all-icr-io -n default -o yaml | sed 's/default/myproject/g' | oc create -n myproject -f -

Deploymentはこんな感じ。imagePullSecretは直前で作成したイメージプルシークレットを指定。

deploy-print-hostname.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: flask-app
  name: flask-app
spec:
  replicas: 4
  selector:
    matchLabels:
      app: flask-app
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: flask-app
    spec:
      containers:
      - image: jp.icr.io/mynamespace/print-hostname
        name: print-hostname
        resources: {}
      imagePullSecrets:
      - name: all-icr-io
status: {}

Deployment作成。

$ oc apply -f deploy-print-hostname.yaml

各ノードにPodがスケジュールされていることを確認(flask-appから始まるPod)。

$ oc get po -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
access-test                  1/1     Running   0          6m36s   172.17.29.22    10.245.64.8   <none>           <none>
flask-app-574649d9b8-4dhhk   1/1     Running   0          13s     172.17.43.133   10.245.0.12   <none>           <none>
flask-app-574649d9b8-4ff9x   1/1     Running   0          13s     172.17.29.36    10.245.64.8   <none>           <none>
flask-app-574649d9b8-br769   1/1     Running   0          13s     172.17.57.8     10.245.64.7   <none>           <none>
flask-app-574649d9b8-qjjr6   1/1     Running   0          13s     172.17.60.249   10.245.0.11   <none>           <none>

全ノードにスケジュールされない場合はDeschedulerとかPod Topology Spread Constraintとかを使う(といいつつレプリカ数増やせば全ノードにスケジュールされそう)。

Deploymentに対してService作成。

$ oc expose deployment flask-app --port 8080

アプリにアクセスするPodの作成

access-testという名前のPodを作成して、このPodからアプリにアクセスします。

pod-access-test.yaml
apiVersion: v1
kind: Pod
metadata:
  name: access-test
spec:
  restartPolicy: OnFailure
  containers:
    - name: curl
      image: curlimages/curl
      imagePullPolicy: Always
      command: ["/bin/sh", "-c", "tail -f /dev/null"]
$ oc apply -f pod-access-test.yaml

この状態でアプリにアクセスしてみると、各Podにリクエストが投げられたことが分かります。

$ oc rsh access-test
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4ff9x</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-br769</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-qjjr6</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4ff9x</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4dhhk</p>/ $

internalTrafficPolicyの設定とアクセス検証

アプリのServiceにspec.internalTrafficPolicy: Localを設定します。

$ oc edit svc flask-app

access-testPodからアプリに複数回アクセスしてみると、1つのPod(flask-app-574649d9b8-4ff9x)のみにリクエストが投げられたことが分かります。。

$ oc rsh access-test
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4ff9x</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4ff9x</p>/ $
/ $ curl flask-app:8080
<p>Hello world from flask-app-574649d9b8-4ff9x</p>/ $

Podのスケジュールされているノードを確認すると、access-testPodとflask-app-574649d9b8-4ff9xPodが同ノードにスケジュールされているので、Internal Traffic Policyが動作していることが確認できました。

$ oc get po -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
access-test                  1/1     Running   0          6m36s   172.17.29.22    10.245.64.8   <none>           <none>
flask-app-574649d9b8-4dhhk   1/1     Running   0          13s     172.17.43.133   10.245.0.12   <none>           <none>
flask-app-574649d9b8-4ff9x   1/1     Running   0          13s     172.17.29.36    10.245.64.8   <none>           <none>
flask-app-574649d9b8-br769   1/1     Running   0          13s     172.17.57.8     10.245.64.7   <none>           <none>
flask-app-574649d9b8-qjjr6   1/1     Running   0          13s     172.17.60.249   10.245.0.11   <none>           <none>

internalTrafficPolicy: Localに該当するPodがないとき

まず、access-testPodの乗るノードにtaintを付けます。

$ oc adm taint node 10.245.64.8 key1=value1:NoSchedule

この状態で、taintありのノード上にあるアプリのPodを削除します。

$ oc delete po flask-app-574649d9b8-4ff9x

アプリのPodが別ノードにスケジュールされ、access-testPodと同ノードにはアプリのPodが存在しない状態になります。

$ oc get po -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
access-test                  1/1     Running   0          21h   172.17.29.22    10.245.64.8   <none>           <none>
flask-app-574649d9b8-4dhhk   1/1     Running   0          21h   172.17.43.133   10.245.0.12   <none>           <none>
flask-app-574649d9b8-6kqfj   1/1     Running   0          82s   172.17.57.50    10.245.64.7   <none>           <none>
flask-app-574649d9b8-br769   1/1     Running   0          21h   172.17.57.8     10.245.64.7   <none>           <none>
flask-app-574649d9b8-qjjr6   1/1     Running   0          21h   172.17.60.249   10.245.0.11   <none>           <none>

この状態でアプリへのアクセスを試みるもアクセスできません。

$ oc rsh access-test
/ $ curl flask-app:8080
curl: (7) Failed to connect to flask-app port 8080 after 1058 ms: Couldn't connect to server
/ $ curl flask-app:8080
curl: (7) Failed to connect to flask-app port 8080 after 1025 ms: Couldn't connect to server
/ $ curl flask-app:8080
curl: (7) Failed to connect to flask-app port 8080 after 1033 ms: Couldn't connect to server
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0