Container Service for Kubernetes (ACK) クラスターで Deployment、StatefulSet、DaemonSet、ジョブ、CronJob などのワークロードを設定する際は、アプリケーションが安定的かつ信頼性の高い方法で実行されるように、複数の要素を考慮する必要があります。
各 Pod の requests と limits の宣言
Kubernetes クラスターのノードに Pod を過密にスケジューリングすると、高負荷を引き起こし、サービスが正常に機能しなくなる可能性があります。Pod を設定する際は、必要な requests と limits を宣言してください。これにより、クラスターは Pod のデプロイメント時にリソース要件に基づいて適切なノードを見つけることができます。
次の例では、Nginx Pod に以下のリソースが設定されています。
CPU リクエスト 1 コア、メモリリクエスト 1024 Mi
CPU リミット 2 コア、メモリリミット 4096 Mi
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
resources: # リソース宣言
requests:
memory: "1024Mi"
cpu: "1000m"
limits:
memory: "4096Mi"
cpu: "2000m"Kubernetes は静的なリソーススケジューリングメカニズムを使用しています。ノードの残存リソースは、次の数式で計算されます:ノードの残存リソース = ノードの総リソース - 割り当て済みリソース。リソースを大量に消費するプログラムを手動で実行した場合、この数式は実際の使用量ではなく割り当て済みリソースに基づいているため、Kubernetes はその実際のリソース使用量を検出できません。
さらに、すべての Pod は resources を宣言する必要があります。Pod が resources を宣言しない場合、Kubernetes はその Pod をノードにスケジューリングした後もリソースを予約しません。これにより、1 つのノードに Pod が過密状態になり、リソース競合が発生する可能性があります。
ACK のリソースプロファイル機能を使用できます。この機能は、過去の使用状況データに基づいてコンテナーレベルのリソース推奨を提供します。これにより、コンテナーの requests と limits の設定が簡素化されます。
起動時にダウンストリームサービスを待機し、即時終了しない
一部のアプリケーションには外部依存関係があります。たとえば、データベース (DB) からデータを読み取る必要があったり、別のサービスの API に依存したりする場合があります。起動時に、これらの依存関係がまだ準備できていないことがあります。従来の 手動による運用保守 (O&M) では、依存関係が満たされない場合にアプリケーションが終了するフェイルファストアプローチがよく用いられます。しかし、Kubernetes では、ほとんどの O&M 操作は自動化されています。たとえば、システムはデプロイメント中に自動的にノードを選択し、アプリケーションを起動します。アプリケーションに障害が発生した場合、システムは自動的に再起動します。負荷が増加した場合、Horizontal Pod Autoscaler (HPA) はアプリケーションを自動的にスケールアウトできます。
たとえば、A が B に依存し、両方が同じノードで実行されている 2 つのアプリケーション A と B を考えます。何らかの理由でノードが再起動すると、A が B より先に起動する可能性があります。この場合、A の依存関係は満たされません。従来の環境で一般的なように A が即座に終了すると、B が起動した後でも自動的に回復せず、手動での介入が必要になります。
Kubernetes クラスターでは、アプリケーションは起動時に依存関係をチェックする必要があります。依存関係が満たされない場合、アプリケーションは即座に終了するのではなく、待機して依存関係をポーリングする必要があります。この動作は Init Container を使用して実装できます。
再起動ポリシーの設定
Pod の実行中に、そのプロセスは多くの理由で終了する可能性があります。たとえば、コードのバグや高いメモリ使用量によってアプリケーションプロセスが終了し、その結果 Pod が終了することがあります。Pod に restartPolicy を設定することで、Pod が終了した後に自動的に再起動するようにできます。
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
spec:
restartPolicy: OnFailure
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6restartPolicy には、次のいずれかの値を設定できます。
Always:コンテナーを自動的に再起動します。OnFailure:コンテナーがゼロ以外のステータスコードで終了した場合にのみ、自動的に再起動します。Never:コンテナーを再起動しません。
ヘルスチェックプローブの設定
プローブを設定して、アプリケーションのデッドロック、スロースタート、またはサービスの障害などの問題に対処できます。プローブは Kubernetes に自動的な障害回復とトラフィックシェーピング機能を提供します。これにより、Kubernetes は異常なコンテナーを自動的に再起動し、準備ができたインスタンスにのみリクエストを送信できます。これは、サービスの高い可用性と安定性を確保するための重要なメカニズムです。
startupProbe(スタートアッププローブ):アプリケーションの起動が完了したかどうかをチェックします。これは、Java アプリケーションのように起動が遅いアプリケーションに役立ちます。スタートアッププローブが成功するまで、レディネスプローブとライブネスプローブは実行されません。これにより、kubelet が起動の遅いアプリケーションを障害と誤認して再起動するのを防ぎます。readinessProbe(レディネスプローブ):トラフィックシェーピングを制御するために使用されます。このプローブが成功した後にのみ、Pod の IP アドレスがサービスの Endpoints リストに追加されます。これにより、外部リクエストは処理準備が整ったコンテナーにのみ送信されるようになります。livenessProbe(ライブネスプローブ):コンテナーのヘルス状態を監視します。プローブがデッドロックやクラッシュを検出すると、kubelet は自動再起動をトリガーして障害回復を促進します。
次の例は、ステートレスな Nginx Deployment のヘルスチェックプローブを設定する方法を示しています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-demo
spec:
replicas: 1 # 本番環境では、高可用性を確保するために 2 以上に設定します
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
ports:
- containerPort: 80
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 500m
# --- ヘルスチェックプローブ ---
# スタートアッププローブ:コンテナー内のアプリケーションが起動したことを確認します。
startupProbe:
httpGet:
path: / # Nginx のデフォルトのルートパスへのアクセスは、起動成功を示します。
port: 80
# アプリケーションの起動に十分な時間を確保します。合計タイムアウト = failureThreshold × periodSeconds、つまり 30 × 10 = 300 秒です。
failureThreshold: 30
periodSeconds: 10
# レディネスプローブ:コンテナーがトラフィックを受け入れる準備ができているかを判断します。
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5 # コンテナー起動後 5 秒でプローブを開始します。
periodSeconds: 5 # 5 秒ごとにプローブを実行します。
timeoutSeconds: 2 # プローブのタイムアウト。
successThreshold: 1 # 1 回の成功で準備完了とマークします。
failureThreshold: 3 # 3 回連続で失敗すると準備未完了とマークします。
# ライブネスプローブ:コンテナーが「生存」しているかを判断し、自動的な障害回復を行います。
# この設定は、一時的なジッターによる不要な再起動を避けるため、readinessProbe よりも緩やかにする必要があります。
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15 # コンテナー起動後 15 秒で最初のプローブを開始し、アプリケーションの初期化と安定化を待ちます。
periodSeconds: 10 # プローブの頻度は readinessProbe よりも低く設定し、システムリソースの消費を抑えます。
timeoutSeconds: 3 # タイムアウトは readinessProbe よりも少し長く設定できます。
successThreshold: 1 # 1 回の成功で生存しているとマークします。
failureThreshold: 3 # 3 回連続で失敗すると (3 × 10 = 30 秒)、kubelet はコンテナーを再起動します。本番環境でダウンタイムなしのローリングデプロイを設定する方法の詳細については、「ダウンタイムゼロのローリングデプロイの実装」をご参照ください。
コンテナーごとに 1 つのプロセス
一部の開発者は、コンテナーを仮想マシン (VM) のように扱います。彼らは、モニタリング、ロギング、sshd プロセス、さらには完全な Systemd など、複数のプロセスを単一のコンテナーで実行します。この方法は、次の問題を引き起こします。
Pod の全体的なリソース使用量を判断するのがより複雑になり、requests と limits を正しく設定するのが難しくなります。
コンテナーが単一のプロセスのみを実行している場合、外部のコンテナーエンジンはそのプロセスが中断したときに即座に検出し、コンテナーを再起動できます。コンテナーが複数のプロセスを実行している場合、外部のコンテナーエンジンはいずれかのプロセスがクラッシュしても検出できません。これにより、コンテナーが正常に機能しなくなる可能性があります。
Kubernetes は、連携して動作する複数のプロセスをサポートしています。たとえば、Nginx と PHP-FPM は Unix ドメインソケットを介して通信できます。これを実現するには、2 つのコンテナーを含む Pod を作成し、コンテナー間で共有されるボリュームに Unix ドメインソケットを格納します。
単一障害点の回避
アプリケーションにインスタンスが 1 つしかない場合、そのインスタンスに障害が発生すると、Kubernetes が自動的に再起動できたとしても、必然的に短いサービス中断が発生します。同様のサービス中断は、アプリケーションを更新したり、新しいバージョンをリリースしたりする際にも発生する可能性があります。
Kubernetes では、Pod を直接管理することは避けてください。代わりに、Deployment または StatefulSet を使用して管理します。また、アプリケーションが少なくとも 2 つの Pod インスタンスで実行されるようにする必要があります。このアプローチにより、システムの高可用性が向上し、単一インスタンスの障害によるサービス中断を防ぐことができます。
関連ドキュメント
ACK は、アプリケーションの段階的リリース、ブルーグリーンデプロイメント、およびその他のリリース戦略を実装できます。詳細については、「デプロイメントとリリース」をご参照ください。
アプリケーション管理のベストプラクティスの詳細については、「ワークロードのベストプラクティス」をご参照ください。
Pod が異常な場合は、「Pod の例外のトラブルシューティング」および「ワークロードに関するよくある質問」を参照して自己チェックを実行できます。