KubernetesマルチコンテナPodにおけるヘルスチェックプローブの動作メカニズム分析

  1. はじめに

皆さん、こんにちは。この2年間、DevOpsエンジニアからマシンラーニングプラットフォームリードエンジニアに戻りました。より具体的に言えば、「クラウドプラットフォーム開発」とGPUの知識を組み合わせた仕事ですね。

そのため、今後もKubernetesや「マシンラーニングプラットフォーム」に関連する内容を更新していきます。長い間お待たせしましたが、ようこそ戻ってきました!

  1. 本題

今日、同僚から質問がありました:1つのPod内で複数のコンテナを実行している場合、片方がダウンするともう片方はどうなるのでしょうか?

確か、プローブの設定方法によって結果が異なるはずだと思い、実際にテストしてみたところ、予想と完全には一致しない結果が得られました。

そこで、今日はこの知識について皆さんと共有します。

  1. 結論(要約)

はい、結論から始めます。皆さんは忙しいので理解できますよね。

テストの結果、以下のことが判明しました:

1つのPodに2つのコンテナが含まれている場合、これらのコンテナがそれぞれ異なるポート(HTTPサービスを例)を公開しているとき、片方のコンテナで以下のことが発生した場合:

  1. Livenessプローブに失敗すると、そのコンテナはKubeletによって停止され、再起動/再構築されます(もちろん、再起動ポリシーがAlwaysであることが条件)。もう片方のコンテナは再起動しません(つまり、Podレベルでの再起動/再構築は発生せず、PodのIPアドレスも変化しません)。

  2. Readinessプローブに失敗すると、Podの状態のReadyカラムは1/2になります。重要なのはServiceがどのように動作するかです。

    1. 1つのServiceがこのPodの2つのポートにトラフィックを負荷分散している場合、Serviceに対応するEndpointはNotReadyになり、Pod内の準備完了しているコンテナにもService経由でアクセスできなくなります。
    2. 2つの異なるServiceがそれぞれPodの2つのポートにトラフィックを負荷分散している場合、残念ながら、対応する2つのEndpointは両方ともNotReadyになります。1つがReadyで1つがNotReadyになるのではありません(これは、当初の私の予想と一致しませんでした)。
  3. テストプロセス


ここまで読んでいただいた方は、好奇心の強い方ですね!

4.1 テスト用イメージの準備

NGINXイメージを使用してプローブ機能のテストを行いたいですが、1つのPod内の2つのコンテナが異なるポートをリッスンするようにするには、イメージを再ビルドしてラップする必要があります。

1. まず、設定ファイルを準備します

  • default.conf
server {
    listen 8080;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

2. 次に、Dockerfileを準備します

  • Dockerfile
FROM nginx

RUN rm /etc/nginx/conf.d/default.conf

COPY default.conf /etc/nginx/conf.d/

EXPOSE 8080

ここではポート番号を8080に指定しています。

3. ビルドを実行します

docker build -t my-custom-nginx-8080:1.0 .

これで最初のイメージが完成しました。次に、8081ポートをリッスンする新しいイメージを作成します。

4. 設定ファイルを更新します

  • default.conf
server {
    listen 8081;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
}

5. Dockerfileを更新します

FROM nginx

RUN rm /etc/nginx/conf.d/default.conf

COPY default.conf /etc/nginx/conf.d/

EXPOSE 8081

6. 2つ目のイメージをビルドします

docker build -t my-custom-nginx-8081:1.0 .

これで2つのイメージの準備が完了しました。次にこれらのイメージをK8sワーカーノードに配置する方法は、各自のやり方で対応してください。イメージリポジトリ経由でも、手動でのコピーでも構いません。

4.2 Deployment YAMLの準備

まず、プローブが通るバージョンを実行して、「1 Pod 2 Container」が起動することを確認します。

  • deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-multi-container
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-multi
  template:
    metadata:
      labels:
        app: nginx-multi
    spec:
      containers:
      - name: web-server-1
        image: my-custom-nginx-8080:1.0
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
      - name: web-server-2
        image: my-custom-nginx-8081:1.0
        ports:
        - containerPort: 8081
        livenessProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 5

4.3 Service YAMLの準備

次に、readinessProbe関連の動作をテストするためのServiceを準備します。

  • svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-combined-service
spec:
  selector:
    app: nginx-multi
  ports:
    - name: port-a
      protocol: TCP
      port: 8080
      targetPort: 8080
    - name: port-b
      protocol: TCP
      port: 8081
      targetPort: 8081

4.4 2つ目のService YAMLの準備

Pod内の2つのコンテナにトラフィックを転送するために、2つの異なるServiceを使用する場合はどうなるでしょうか?これも試してみます:

  • svc-separate.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-first
spec:
  selector:
    app: nginx-multi
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-second
spec:
  selector:
    app: nginx-multi
  ports:
    - protocol: TCP
      port: 8081
      targetPort: 8081

4.5 テストプロセス

YAMLを適用後、Deployment設定内のlivenessProbe.httpGet.pathreadinessProbe.httpGet.pathを正しい/から404を引き起こす/testに順次変更し、Podの状態変化、Service/Endpointの状態変化を観察すれば完了です。

  1. 結論

前に記載した結論を再掲します:

1つのPodに2つのコンテナが含まれている場合、これらのコンテナがそれぞれ異なるポート(HTTPサービスを例)を公開しているとき、片方のコンテナで以下のことが発生した場合:

  1. Livenessプローブに失敗すると、そのコンテナはKubeletによって停止され、再起動/再構築されます(もちろん、再起動ポリシーがAlwaysであることが条件)。もう片方のコンテナは再起動しません(つまり、Podレベルでの再起動/再構築は発生せず、PodのIPアドレスも変化しません)。
  2. Readinessプローブに失敗すると、Podの状態のReadyカラムは1/2になります。重要なのはServiceがどのように動作するかです。
    1. 1つのServiceがこのPodの2つのポートにトラフィックを負荷分散している場合、Serviceに対応するEndpointはNotReadyになり、Pod内の準備完了しているコンテナにもService経由でアクセスできなくなります。
    2. 2つの異なるServiceがそれぞれPodの2つのポートにトラフィックを負荷分散している場合、残念ながら、対応する2つのEndpointは両方ともNotReadyになります。1つがReadyで1つがNotReadyになるのではありません(これは、当初の私の予想と一致しませんでした)。

タグ: Kubernetes Pod ヘルスチェックプローブ LivenessProbe ReadinessProbe

7月9日 20:32 投稿