Kubernetesデプロイメントでダウンタイムゼロのローリングアップデートを実行する方法

Kubernetesのローリングアップデートを、Readiness Probe、maxSurge、maxUnavailable、Graceful Shutdownを用いて設定します。

Kubernetesデプロイメントでダウンタイムゼロのローリングアップデートを実行する方法

Kubernetesのローリングアップデートは、Podが準備完了しているタイミングとシャットダウンの方法について、デプロイメントとアプリケーションの間で合意が取れていれば、目に見える停止なくPodを置き換えることができます。デフォルトの戦略も役立ちますが、不適切なReadiness Probe、互換性のないリリース、または処理中のリクエストのドロップからは守ってくれません。

しかし、真のダウンタイムゼロを達成するには、デフォルトのKubernetes設定以上のものが必要です。デプロイメントマニフェスト、アプリケーションのヘルスエンドポイント、およびGraceful Terminationプロセス間の慎重な調整が求められます。このガイドでは、Kubernetesデプロイメントを設定して、アプリケーションの更新がシームレスでエンドユーザーに気づかれないようにするための、包括的でステップバイステップのアプローチを提供します。

このガイドでは、Readiness Probe、maxSurgemaxUnavailable、およびGraceful Terminationについて説明し、ロールアウト中にサービスがキャパシティを維持できるようにします。

ダウンタイムゼロのための前提条件

Kubernetesマニフェストを設定する前に、基盤となるアプリケーションがダウンタイムゼロのデプロイメントをサポートするために、特定の原則に従う必要があります。

  1. アプリケーションの後方互換性: アプリケーションの新旧両方のバージョンが同時に実行されている短期間、それらは共有リソース(データベース、キュー、キャッシュ)と互換性がなければなりません。
  2. 冪等性: 両方のバージョンで処理される可能性のある操作は、悪影響を及ぼすことなく繰り返し可能でなければなりません。
  3. Graceful Termination: アプリケーションは、Kubernetesから送信されるSIGTERMシグナルを認識し、新しい接続の受け入れを適切に停止し、終了前に処理中のリクエストを完了するようにプログラムされている必要があります。

Kubernetesローリングアップデート戦略の理解

KubernetesデプロイメントはデフォルトでRollingUpdate戦略を使用します。この方法は、新しいバージョンが稼働する前に古いアプリケーションバージョンが完全に停止されないようにし、2つの主要なパラメータを使用して移行を管理します。

パラメータ 説明 ダウンタイムゼロへの影響
maxSurge 希望するレプリカ数を超えて作成できるPodの最大数を定義します。絶対数またはパーセンテージ(デフォルト: 25%)で指定できます。 ロールアウトの速度を制御し、一時的にキャパシティが増加することを保証します。
maxUnavailable 更新中に利用不可になる可能性のあるPodの最大数を定義します。絶対数またはパーセンテージ(デフォルト: 25%)で指定できます。 ダウンタイムゼロにとって重要です。 これを0%に設定すると、新しいPodが完全にReadyになるまで、サービス中のPodは終了されません。

ダウンタイムゼロのための推奨戦略

最高の可用性を得るためには、多くの場合、キャパシティの損失をゼロにする以下の設定が最適です。

  • maxUnavailable: 0(キャパシティが低下しないようにする)。
  • maxSurge: 1 または 25%(キャパシティが一時的に目標を超えることを許可し、古いPodが停止される前に新しいPodが準備完了になることを保証する)。

ステップ1: Readiness Probeの実装

Readiness Probeは、ダウンタイムゼロの更新を保証するための最も重要なメカニズムです。Kubernetesはこのプローブに依存して、新しいPodがユーザートラフィックを受信する準備ができているかどうか、および古いPodがまだアクティブにトラフィックを処理しているかどうかを判断します。

Liveness ProbeとReadiness Probe

  • Liveness Probe: コンテナが正常で機能しているかどうかをKubernetesに伝えます。失敗した場合、コンテナは再起動されます。
  • Readiness Probe: コンテナがリクエストを処理する準備ができているかどうかをKubernetesに伝えます。失敗した場合、Podは関連するServiceのエンドポイントから削除され、準備ができるまでトラフィックがそらされます。

ローリングアップデートでは、Readiness Probeが移行をゲートするために使用されます。Kubernetesは、新しく作成されたPodがReadinessチェックに合格するまで、古いPodの終了を開始しません。

# deployment.yaml 抜粋
spec:
  containers:
  - name: my-app
    image: myregistry/my-app:v2.0
    ports:
    - containerPort: 8080
    
    # --- Readiness Probe設定 ---
    readinessProbe:
      httpGet:
        path: /health/ready
        port: 8080
      initialDelaySeconds: 15  # 最初のプローブ試行までの待機時間
      periodSeconds: 5         # チェックを実行する頻度
      timeoutSeconds: 3
      failureThreshold: 3      # Podを準備未完了とマークするまでの連続失敗回数

    # --- Liveness Probe設定(標準的なヘルスチェック) ---
    livenessProbe:
      httpGet:
        path: /health/live
        port: 8080
      initialDelaySeconds: 60
      periodSeconds: 10

ヒント: アプリケーションの/health/readyエンドポイントが、初期化、データベース接続、およびその他の外部依存関係が完全に動作している場合にのみ、成功コード(HTTP 200-299)を返すようにしてください。

ステップ2: デプロイメント戦略の設定

真のダウンタイムゼロを義務付けるために、利用可能なレプリカ数の低下を防ぐようにローリングアップデート戦略を明示的に設定します。

この設定では、Kubernetesは最初に新しいPodを作成します(maxSurge: 1)。新しいPodがReadiness Probeに合格すると、その後にKubernetesは古いPodを終了します。maxUnavailableが0であるため、サービスキャパシティは目標のレプリカ数を下回ることはありません。

# deployment.yaml 抜粋
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:
    # ... コンテナ仕様 ...

ステップ3: Graceful Terminationの確保

堅牢なReadiness Probeがあっても、アプリケーションが終了シグナルを受信した瞬間にシャットダウンすると、処理中のリクエストがドロップされるリスクがあります。

Kubernetesは特定の終了シーケンスに従います。

  1. PodはTerminatingとしてマークされます。
  2. PodはServiceエンドポイントから削除されます(トラフィックのルーティングが停止します)。
  3. pre-stopフック(定義されている場合)が実行されます。
  4. コンテナはSIGTERMシグナルを受信します。
  5. KubernetesはterminationGracePeriodSeconds(デフォルト: 30秒)で定義された期間待機します。
  6. コンテナがまだ実行中の場合は、譲歩できないSIGKILLを受信します。

Graceful Shutdownを確実にするために、アプリケーションはSIGTERMを処理し、terminationGracePeriodSecondsはアプリケーションが既存のリクエストを完了するのに十分な長さでなければなりません。

# deployment.yaml 抜粋、Podテンプレート仕様内
spec:
  terminationGracePeriodSeconds: 45 # Podレベルの設定
  containers:
  - name: my-app
    image: myregistry/my-app:v2.0
    lifecycle:
      preStop:
        exec:
          # エンドポイントの更新と外部ロードバランサーがドレインする時間を与える。
          command: ["/bin/sh", "-c", "sleep 10"]

ベストプラクティス: アプリケーションはSIGTERMを受信したら新しい作業の受け入れを停止し、終了する前に処理中のリクエストを完了する必要があります。terminationGracePeriodSecondsを45秒や60秒など少し長めに設定すると、低速なリクエストに対する強制終了を防ぐのに役立ちます。

ステップ4: 更新の実行と監視

デプロイメントマニフェストに最適化された戦略と堅牢なプローブが含まれていれば、更新の実行は簡単です。

  1. イメージタグの更新: デプロイメントマニフェストを変更して、新しいイメージバージョン(例: v2.0からv2.1)を反映させます。

  2. 設定の適用:

    kubectl apply -f deployment.yaml
    

    または、イメージを直接パッチすることもできます。

    kubectl set image deployment/my-web-deployment my-app=myregistry/my-app:v2.1
    
  3. ロールアウトステータスの監視: Kubernetesが各段階を進むのを監視し、準備完了のPod数が希望する数を下回らないことを確認します。

    kubectl rollout status deployment/my-web-deployment
    
  4. Podの可用性の確認: Podのステータスを観察して、古いPod(v2.0)が新しいPod(v2.1)が完全に準備完了になった後にのみGracefulに終了されることを確認します。

    kubectl get pods -l app=my-web-deployment -w
    

高度な考慮事項

Pod Disruption Budgets(PDB)の使用

デプロイメント戦略がロールアウトを管理する一方で、**Pod Disruption Budget(PDB)**は、ノードのドレインや一部のクラスタメンテナンス操作などの自発的な中断を制限します。計画外の障害をすべて防ぐわけではありませんが、Kubernetesと自動化ツールに尊重すべき最小可用性目標を提供します。

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app-pdb
spec:
  minAvailable: 75%  # 常に少なくとも75%のレプリカが利用可能であることを保証する
  selector:
    matchLabels:
      app: my-web-deployment

初期遅延の重要性

アプリケーションのウォームアップに時間がかかる場合は、initialDelaySecondsperiodSeconds、およびfailureThresholdを調整して、Readinessが実際の起動動作を反映するようにします。Readiness Probeの失敗はPodをServiceエンドポイントから除外します。Liveness Probeの失敗はコンテナを再起動し、クラッシュループを引き起こす可能性があります。

安全にロールアウトする

Kubernetesで真のダウンタイムゼロのローリングアップデートを達成するには、堅牢なプラットフォーム設定と規律あるアプリケーション開発の組み合わせが必要です。Readiness Probeを活用して動作状態を通知し、デプロイメント戦略(maxUnavailable: 0)を調整してキャパシティを維持し、Graceful Terminationハンドラを実装することで、ユーザーへのサービスを中断することなく、アプリケーションの更新を確実に実行できます。ステージング環境で更新プロセスを徹底的にテストし、終了猶予期間とプローブのロジックを検証してください。