Kubernetes Deploymentでゼロダウンタイムローリングアップデートを実行する方法
はじめに
現代のマイクロサービスアーキテクチャでは、アプリケーションの更新中も継続的な可用性を維持することが、譲れない要件となっています。Kubernetes Deploymentは、このプロセスを簡素化するために、古いバージョンのPodを新しいバージョンに段階的に置き換えるように設計された自動化されたローリングアップデートを提供します。
しかし、真のゼロダウンタイムを実現するには、デフォルトのKubernetes構成だけでは不十分です。Deploymentマニフェスト、アプリケーションのヘルスエンドポイント、およびグレースフルターミネーションプロセスとの間の慎重な連携が必要です。このガイドでは、エンドユーザーには見えないシームレスなアプリケーション更新を保証するために、Kubernetes Deploymentを構成するための包括的かつ段階的なアプローチを提供します。
レディネスプローブの重要な役割、デプロイメント戦略パラメータ(maxSurgeとmaxUnavailable)の調整方法、およびデプロイメント移行中のサービス中断を排除するためのアプリケーション終了に関するベストプラクティスについて説明します。
ゼロダウンタイムの前提条件
Kubernetesマニフェストを構成する前に、基盤となるアプリケーションはゼロダウンタイムデプロイメントをサポートするために、特定の原則を順守する必要があります。
- アプリケーションの下位互換性(Backward Compatibility): 古いバージョンと新しいバージョンのアプリケーションが同時に実行される短い期間において、それらは共有リソース(データベース、キュー、キャッシュ)と互換性がある必要があります。
- 冪等性(Idempotency): 両方のバージョンによって処理される可能性のある操作は、悪影響なしに繰り返し実行できる必要があります。
- グレースフルターミネーション(Graceful Termination): アプリケーションは、Kubernetesから送信される
SIGTERMシグナルを認識し、終了する前にインフライトリクエスト(処理中のリクエスト)を完了させながら、新しい接続の受け入れをグレースフルに停止するようにプログラムされている必要があります。
Kubernetesローリングアップデート戦略の理解
Kubernetes DeploymentはデフォルトでRollingUpdate戦略を使用します。この方法では、新しいバージョンが稼働する前に古いアプリケーションバージョン全体が停止されることがないようにし、主に2つのパラメータを使用して移行を管理します。
| パラメータ | 説明 | ゼロダウンタイムへの影響 |
|---|---|---|
maxSurge |
望ましいレプリカ数を超えて作成できるPodの最大数を定義します。絶対数またはパーセンテージで指定できます(デフォルト:25%)。 | ロールアウトの速度を制御し、一時的にキャパシティが増加することを保証します。 |
maxUnavailable |
更新中に利用できなくなるPodの最大数を定義します。絶対数またはパーセンテージで指定できます(デフォルト:25%)。 | ゼロダウンタイムにとって極めて重要です。 これを0%に設定すると、新しいPodが完全にReadyになるまで、サービスを提供しているPodは終了されません。 |
ゼロダウンタイムのための推奨戦略
最高の可用性を実現するために、最良の構成は、キャパシティの損失によるダウンタイムをゼロにすることを目指します。
maxUnavailable: 0(キャパシティが低下しないことを保証します)。maxSurge: 1または25%(一時的にターゲットを超えるキャパシティを許可し、古いPodが停止される前に新しいPodが準備完了になることを保証します)。
ステップ1:レディネスプローブの実装
レディネスプローブ (Readiness Probe) は、ゼロダウンタイム更新を確実にするための最も重要なメカニズムです。Kubernetesは、このプローブに依存して、新しいPodがユーザーのトラフィックを受信する準備ができているか、古いPodがまだトラフィックをアクティブに処理しているかを判断します。
LivenessとReadinessの比較
- Liveness Probe: コンテナが正常で機能しているかどうかをKubernetesに伝えます。失敗した場合、コンテナは再起動されます。
- Readiness Probe: コンテナがリクエストを処理する準備ができているかどうかをKubernetesに伝えます。失敗した場合、Podは関連付けられたServiceエンドポイントから削除され、準備が整うまでトラフィックをそらします。
ローリングアップデートの場合、レディネスプローブは移行をゲートするために使用されます。新しく作成されたPodがレディネスチェックに合格するまで、Kubernetesは古いPodの終了に進みません。
# deployment.yaml excerpt
spec:
containers:
- name: my-app
image: myregistry/my-app:v2.0
ports:
- containerPort: 8080
# --- Readiness Probe Configuration ---
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15 # 最初のプローブ試行までに待機する時間
periodSeconds: 5 # チェックを実行する頻度
timeoutSeconds: 3
failureThreshold: 3 # PodをNot Readyとマークする連続失敗回数
# --- Liveness Probe Configuration (標準的なヘルスチェック) ---
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
ヒント: アプリケーションの
/health/readyエンドポイントは、初期化、データベース接続、その他の外部依存関係が完全に動作している場合にのみ成功コード(HTTP 200-299)を返すようにしてください。
ステップ2:Deployment戦略の構成
真のゼロダウンタイムを義務付けるために、利用可能なレプリカ数が低下するのを防ぐよう、ローリングアップデート戦略を明示的に構成します。
この構成では、Kubernetesはまず新しいPodを1つ作成します(maxSurge: 1)。新しいPodがレディネスプローブに合格して初めて、Kubernetesは古いPodを終了します。maxUnavailableが0であるため、サービスキャパシティはターゲットのレプリカ数を下回ることはありません。
# deployment.yaml excerpt
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-deployment
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
# キャパシティが望ましいレプリカ数 (4) を下回らないように保証する
maxUnavailable: 0
# ロールアウト中に1つの追加のPodを作成することを許可する
maxSurge: 1
template:
# ... container specification ...
ステップ3:グレースフルターミネーションの確保
堅牢なレディネスプローブがあったとしても、アプリケーションが終了シグナルを受け取った瞬間に即座にシャットダウンした場合、インフライトリクエストを失うリスクがあります。
Kubernetesは特定の終了シーケンスに従います。
- PodがTerminatingとしてマークされます。
- PodがServiceエンドポイントから削除されます(トラフィックのルーティングが停止します)。
- pre-stopフック(定義されている場合)が実行されます。
- コンテナが
SIGTERMシグナルを受け取ります。 - Kubernetesは
terminationGracePeriodSecondsで定義された期間(デフォルト:30秒)待機します。 - コンテナがまだ実行中の場合、容赦ない
SIGKILLを受け取ります。
グレースフルシャットダウンを確実にするには、アプリケーションがSIGTERMを処理する必要があり、既存のリクエストを完了するのに十分な長さのterminationGracePeriodSecondsを設定する必要があります。
# deployment.yaml excerpt, inside the container spec
terminationGracePeriodSeconds: 45 # グレースフルシャットダウンのために時間を延長
containers:
- name: my-app
image: myregistry/my-app:v2.0
lifecycle:
preStop:
exec:
# 例: 接続を直ちにドレインするためのスクリプトを実行
command: ["/bin/sh", "-c", "sleep 10"]
ベストプラクティス: PodがReadiness Probeに失敗してから(ステップ2)、
SIGTERMを受け取るまで(ステップ4)の時間は非常に重要です。アプリケーションがSIGTERMを正しく処理する場合、terminationGracePeriodSecondsをわずかに長く設定する(例:45秒または60秒)ことで、強制終了を防ぐことができます。
ステップ4:更新の実行と監視
Deploymentマニフェストに最適化された戦略と堅牢なプローブが含まれたら、更新の実行は簡単です。
-
イメージタグの更新: デプロイメントマニフェストを変更し、新しいイメージバージョン(例:
v2.0からv2.1)を反映させます。 -
構成の適用:
bash kubectl apply -f deployment.yamlまたは、イメージを直接パッチすることもできます。
bash kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1 -
ロールアウトステータスの監視: 準備完了のPodの数が望ましい数を下回っていないことを確認しながら、Kubernetesが段階を進めるのを監視します。
bash kubectl rollout status deployment/my-web-deployment -
Podの可用性の確認: 古いPod(v2.0)が新しいPod(v2.1)が完全に準備完了になった後にのみグレースフルに終了していることを確認するために、Podステータスを監視します。
bash kubectl get pods -l app=my-web-deployment -w
高度な考慮事項
Pod Disruption Budget (PDB) の使用
デプロイメント戦略が自発的な更新を管理するのに対し、Pod Disruption Budget (PDB) は、計画外の中断(例:ノードのメンテナンス、クラスターのアップグレード)が発生した場合でも、最小限のPodが利用可能であることを保証します。PDBはローリングアップデートの速度を直接制御しませんが、セーフティネットとして機能します。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 75% # 常にレプリカの少なくとも75%が利用可能であることを保証する
selector:
matchLabels:
app: my-web-deployment
Initial Delayの重要性
アプリケーションのウォームアップに時間がかかる場合(例:大きな構成ファイルのロードやキャッシュの確立)、Readiness ProbeのinitialDelaySecondsが十分に長く設定されていることを確認してください。プローブが早すぎるタイミングでチェックを行い失敗した場合、Podは異常とマークされ、クラッシュループに陥り、デプロイメント全体が停止する可能性があります。
結論
Kubernetesで真のゼロダウンタイムローリングアップデートを実現することは、堅牢なプラットフォーム構成と規律あるアプリケーション開発の組み合わせです。Readiness Probeを適切に活用して稼働状況を通知し、Deployment戦略(maxUnavailable: 0)を調整してキャパシティを維持し、グレースフルターミネーションハンドラを実装することで、ユーザーへのサービスを中断することなく、アプリケーション更新を確実に実行できます。終了猶予期間とプローブロジックを検証するために、常にステージング環境で更新プロセスを徹底的にテストしてください。