- はじめに
皆さん、こんにちは。この2年間、DevOpsエンジニアからマシンラーニングプラットフォームリードエンジニアに戻りました。より具体的に言えば、「クラウドプラットフォーム開発」とGPUの知識を組み合わせた仕事ですね。
そのため、今後もKubernetesや「マシンラーニングプラットフォーム」に関連する内容を更新していきます。長い間お待たせしましたが、ようこそ戻ってきました!
- 本題
今日、同僚から質問がありました:1つのPod内で複数のコンテナを実行している場合、片方がダウンするともう片方はどうなるのでしょうか?
確か、プローブの設定方法によって結果が異なるはずだと思い、実際にテストしてみたところ、予想と完全には一致しない結果が得られました。
そこで、今日はこの知識について皆さんと共有します。
- 結論(要約)
はい、結論から始めます。皆さんは忙しいので理解できますよね。
テストの結果、以下のことが判明しました:
1つのPodに2つのコンテナが含まれている場合、これらのコンテナがそれぞれ異なるポート(HTTPサービスを例)を公開しているとき、片方のコンテナで以下のことが発生した場合:
-
Livenessプローブに失敗すると、そのコンテナはKubeletによって停止され、再起動/再構築されます(もちろん、再起動ポリシーがAlwaysであることが条件)。もう片方のコンテナは再起動しません(つまり、Podレベルでの再起動/再構築は発生せず、PodのIPアドレスも変化しません)。
-
Readinessプローブに失敗すると、Podの状態のReadyカラムは1/2になります。重要なのはServiceがどのように動作するかです。
- 1つのServiceがこのPodの2つのポートにトラフィックを負荷分散している場合、Serviceに対応するEndpointはNotReadyになり、Pod内の準備完了しているコンテナにもService経由でアクセスできなくなります。
- 2つの異なるServiceがそれぞれPodの2つのポートにトラフィックを負荷分散している場合、残念ながら、対応する2つのEndpointは両方ともNotReadyになります。1つがReadyで1つがNotReadyになるのではありません(これは、当初の私の予想と一致しませんでした)。
-
テストプロセス
ここまで読んでいただいた方は、好奇心の強い方ですね!
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.pathとreadinessProbe.httpGet.pathを正しい/から404を引き起こす/testに順次変更し、Podの状態変化、Service/Endpointの状態変化を観察すれば完了です。
- 結論
前に記載した結論を再掲します:
1つのPodに2つのコンテナが含まれている場合、これらのコンテナがそれぞれ異なるポート(HTTPサービスを例)を公開しているとき、片方のコンテナで以下のことが発生した場合:
- Livenessプローブに失敗すると、そのコンテナはKubeletによって停止され、再起動/再構築されます(もちろん、再起動ポリシーがAlwaysであることが条件)。もう片方のコンテナは再起動しません(つまり、Podレベルでの再起動/再構築は発生せず、PodのIPアドレスも変化しません)。
- Readinessプローブに失敗すると、Podの状態のReadyカラムは1/2になります。重要なのはServiceがどのように動作するかです。
- 1つのServiceがこのPodの2つのポートにトラフィックを負荷分散している場合、Serviceに対応するEndpointはNotReadyになり、Pod内の準備完了しているコンテナにもService経由でアクセスできなくなります。
- 2つの異なるServiceがそれぞれPodの2つのポートにトラフィックを負荷分散している場合、残念ながら、対応する2つのEndpointは両方ともNotReadyになります。1つがReadyで1つがNotReadyになるのではありません(これは、当初の私の予想と一致しませんでした)。