すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:アプリケーションのゼロダウンタイムデプロイ

最終更新日:Dec 11, 2025

Alibaba Cloud Container Service for Kubernetes (ACK) クラスターでサービスを中断せずにアプリケーションを更新するには、readiness プローブ、readinessGatespreStop フック、および Server Load Balancer (SLB) の接続ドレインを使用して Deployment を構成します。この設定により、スムーズなトラフィック移行が可能になり、アップグレード中の高可用性が維持されます。

仕組み

RollingUpdate 戦略は、ライブトラフィックを処理するのに十分なレプリカを維持しながら、Pod を段階的に置き換えることで、ステートレスワークロードのアップグレードを調整します。コアプロセスには、いくつかの段階が含まれます。

  1. 起動段階:Kubernetes は新しい Pod (v2) を作成します。システムは、この Pod が readiness プローブに合格し、リクエストを処理する準備ができたことを確認するまで待機します。このプローブが成功するまで、Pod は Service トラフィックから分離されます。

  2. トラフィック切り替え段階:この段階では、Kubernetes の状態と基盤となるインフラストラクチャが同期されます。新しい Pod が内部プローブに合格すると、その IP が Service の Endpoints に追加されます。ただし、構成された readinessGates により、Cloud Controller Manager が SLB バックエンドサーバーグループに正常に登録するまで、Pod は完全な Ready 状態としてマークされません。これにより、ロードバランサーが新しいインスタンスへのトラフィックのルーティングを開始する前に、そのインスタンスを認識することが保証されます。同時に、古い Pod は SLB から登録解除され、終了シグナルを受信するため、新しいリクエストを受け付けなくなります。

    readinessGates の仕組みの詳細については、「readinessGates の仕組み」をご参照ください。
  3. グレースフルシャットダウン段階:この段階では、古いインスタンスの安全な終了を調整します。Pod が終了シグナルを受信すると、Kubelet は preStop ライフサイクルフックを呼び出し、アプリケーションが構成された terminationGracePeriodSeconds 内で処理中のリクエストを完了するための時間を与えます。並行して、SLB は接続ドレインを実行します。つまり、既存の接続を維持しながら、新しい接続が Pod にルーティングされるのを停止します。この協調的なシャットダウンにより、Pod が削除される前にリクエストがドロップされないようにすることができます。

前提条件

  • クラスター:バージョン 1.24 以降。クラスターのアップグレード方法の詳細については、「クラスターのアップグレード」をご参照ください。

  • コンポーネント:cloud-controller-manager バージョン v2.10.0 以降。コンポーネントの詳細については、「Cloud Controller Manager」をご参照ください。

サンプルアプリケーションのデプロイ

以下のいずれかの方法を使用して、ステートレス NGINX アプリケーションをデプロイします。

コンソール

  1. ACK クラスターページで、対象クラスターの名前をクリックします。左側のナビゲーションウィンドウで、Workloads > Deployments を選択します。

  2. 展開 ページで、YAML のリソースの作成 をクリックします。次のコードをエディターにコピーし、デプロイ をクリックします。

    サンプルアプリケーションの YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-demo
    spec:
      replicas: 1                 # 本番環境の高可用性のためには 2 以上に設定します。ここではデモ目的で 1 に設定しています。
      selector:
        matchLabels:
          app: nginx-demo
      # ローリングアップデート戦略:更新中のサービスの可用性を確保します。
      # strategy:
        # type: RollingUpdate     # Deployment のデフォルト戦略です。
        # rollingUpdate:
          # maxUnavailable: "25%" # デフォルト。更新中に利用不可にできる Pod の最大 25%。
          # maxSurge: "25%"       # デフォルト。希望するレプリカ数を超えて作成できる Pod の最大 25%。
      template:
        metadata:
          labels:
            app: nginx-demo 
        spec:
          # Pod レベルのグレースフルシャットダウンの制限。preStop の実行時間とアプリのクリーンアップ時間の合計を超える必要があります。
          terminationGracePeriodSeconds: 60 
          readinessGates:
          - conditionType: service.readiness.alibabacloud.com/nginx-demo-service # nginx-demo-service の Readiness Gate を構成します。
          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
            # --- ヘルスチェックプローブ ---
            # Startup Probe:コンテナー内のアプリケーションが起動したことを確認します。
            startupProbe:
              httpGet:
                path: / # 成功は NGINX のルートパスがアクセス可能であることを示します。
                port: 80
              # 起動に十分な時間を許可します。合計タイムアウト = failureThreshold * periodSeconds。
              # ここでは:30 * 10 = 300 秒。
              failureThreshold: 30
              periodSeconds: 10
            # Readiness Probe:コンテナーがトラフィックを受け入れる準備ができているかを確認します。
            readinessProbe:
              httpGet:
                path: /
                port: 80
              initialDelaySeconds: 5  # コンテナー起動後 5 秒でプローブを開始します。
              periodSeconds: 5        # 5 秒ごとにプローブします。
              timeoutSeconds: 2       # プローブのタイムアウト。
              successThreshold: 1     # 1 回の成功で Pod は準備完了とマークされます。
              failureThreshold: 3     # 3 回連続で失敗すると Pod は準備未完了とマークされます。
            # --- サービスのグレースフルシャットダウン構成 ---
            lifecycle:
              preStop:
                exec:
                  # シャットダウン前に処理中の接続を処理するためのカスタムフックを定義します。
                  # 'sleep' だけに頼ると、適切なグレースフル終了が保証されない場合があります。
                  command: ["sh", "-c", "sleep 30 && /usr/sbin/nginx -s quit"]
    ---           
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-demo-service
      annotations:
        # SLB 接続ドレインのタイムアウト。アプリケーションの preStop ロジックと一致させる必要があります。範囲:10〜900 秒。
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout: "30" 
        # SLB 接続ドレインを有効にします。
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain: "on"
    spec:
      type: LoadBalancer
      selector:
        app: nginx-demo 
      ports:
        - protocol: TCP
          port: 80
  3. ダイアログボックスで、デプロイメントを見つけて ビュー をクリックします。Pod のステータスが 実行中 であることを確認します。

kubectl

  1. kubectl を使用してクラスターに接続します。パブリックアクセスがないクラスターの場合は、[クラスター情報] ページで [ワークベンチを使用してクラスターを管理] をクリックして、内部ネットワーク経由で接続します。

  2. 次の内容で nginx-demo.yaml という名前のファイルを作成します。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-demo
    spec:
      replicas: 1                 # 本番環境では、高可用性を確保するためにこれを 2 以上に設定します。ここではローリングデプロイの検証を容易にするために 1 に設定しています。
      selector:
        matchLabels:
          app: nginx-demo
      # ローリングアップデート戦略:更新中にサービスが中断されないようにします。
      # strategy:
        # type: RollingUpdate     # デプロイメントワークロードのデフォルト戦略は RollingUpdate です。
        # rollingUpdate:
          # maxUnavailable: "25%" # デフォルト値。更新プロセス中に利用不可にできる Pod の最大 25%。
          # maxSurge: "25%"       # デフォルト値。更新プロセス中に Pod の数が希望のレプリカ数を最大 25% 超えることができます。
      template:
        metadata:
          labels:
            app: nginx-demo 
        spec:
          # Pod レベルのグレースフルシャットダウンの制限。preStop の実行時間とアプリのクリーンアップ時間の合計を超える必要があります。
          terminationGracePeriodSeconds: 60 
          readinessGates:
          - conditionType: service.readiness.alibabacloud.com/nginx-demo-service # nginx-demo-service の Readiness Gate を構成します。
          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
            # --- ヘルスチェックプローブ ---
            # Startup Probe:コンテナー内のアプリケーションが起動したことを確認します。
            startupProbe:
              httpGet:
                path: / # 成功は NGINX のルートパスがアクセス可能であることを示します。
                port: 80
              # 起動に十分な時間を許可します。合計タイムアウト = failureThreshold * periodSeconds。
              # ここでは:30 * 10 = 300 秒。
              failureThreshold: 30
              periodSeconds: 10
            # Readiness Probe:コンテナーがトラフィックを受け入れる準備ができているかを確認します。
            readinessProbe:
              httpGet:
                path: /
                port: 80
              initialDelaySeconds: 5  # コンテナー起動後 5 秒でプローブを開始します。
              periodSeconds: 5        # 5 秒ごとにプローブします。
              timeoutSeconds: 2       # プローブのタイムアウト。
              successThreshold: 1     # 1 回の成功で Pod は準備完了とマークされます。
              failureThreshold: 3     # 3 回連続で失敗すると Pod は準備未完了とマークされます。
            # --- サービスのグレースフルシャットダウン構成 ---
            lifecycle:
              preStop:
                exec:
                  # シャットダウン前に処理中の接続を処理するためのカスタムフックを定義します。
                  # 'sleep' だけに頼ると、適切なグレースフル終了が保証されない場合があります。
                  command: ["sh", "-c", "sleep 30 && /usr/sbin/nginx -s quit"]
    ---           
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-demo-service
      annotations:
        # SLB 接続ドレインのタイムアウト。アプリケーションの preStop ロジックと一致させる必要があります。範囲:10〜900 秒。
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout: "30" 
        # SLB 接続ドレインを有効にします。
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain: "on"
    spec:
      type: LoadBalancer
      selector:
        app: nginx-demo 
      ports:
        - protocol: TCP
          port: 80
  3. 構成を適用して、アプリケーションと Service をデプロイします。

    kubectl apply -f nginx-demo.yaml
  4. Pod のステータスが 実行中 であることを確認します。

    kubectl get pod | grep nginx-deployment-demo
  • Pod readiness プローブ

    • startupProbe:起動が遅いワークロード (例:Java アプリケーション) が初期化されたことを確認するのに最適です。startup プローブが成功するまで liveness プローブと readiness プローブは一時停止され、Kubelet が遅い起動のためにコンテナーを時期尚早に再起動するのを防ぎます。

    • readinessProbe:コンテナーが外部トラフィックを処理する準備ができているかどうかを判断します。成功すると、Pod の IP アドレスが Service の Endpoints に追加され、トラフィックフローが有効になります。

    • readinessGates:準備完了のための追加の前提条件を定義します。Pod は、標準の readinessProbereadinessGates の特定の条件の両方が満たされた場合にのみ、完全に準備ができており、トラフィックを受信できると見なされます。

  • グレースフルシャットダウン

    • アプリケーションのグレースフルシャットダウン

      • preStop:コンテナーが終了する直前に実行されるライフサイクルフック。このフックを使用して、アプリケーションのグレースフルシャットダウンをトリガーし、プロセスが停止する前に処理中のリクエストが完了するようにします。

        アプリケーションロジックに合わせてカスタムフックを定義してください。sleep コマンドだけに頼るのは信頼性が低く、不完全なシャットダウンにつながる可能性があります。
      • terminationGracePeriodSeconds:Kubernetes が Pod を強制的に強制終了 (SIGKILL) する前に、Pod が正常にシャットダウンするのを待つ期間。デフォルト:30 秒。この値は、preStop フックの実行とアプリケーションの内部クリーンアッププロセスの合計期間を超える必要があります。

    • SLB 接続ドレイン

      • service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain:SLB インスタンスで接続ドレインを有効にするためのアノテーション。

      • service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout:SLB 接続ドレインのタイムアウト (秒単位) を設定します。この値は、preStop フックで処理中のリクエストを処理するために必要な時間と一致させる必要があります。

  • ローリングアップデート戦略

    • strategy:デフォルトの Deployment 戦略は RollingUpdate です。古い Pod を新しい Pod で段階的に置き換えます。新しい Pod は、対応する古い Pod が終了する前に作成および検証され、ロールアウト全体でサービスの可用性を確保します。

    • maxUnavailable:更新中に利用不可にできる Pod の最大数 (またはパーセンテージ)。デフォルト:25%。

    • maxSurge:更新中に希望のレプリカ数を超えて作成できる追加の Pod の最大数 (またはパーセンテージ)。値を大きくするとロールアウトは加速しますが、リソース消費量が増加します。デフォルト:25%。

ゼロダウンタイムのローリングアップデートの検証

  1. kubectl を使用してクラスターに接続します

  2. サンプルアプリケーションの外部エンドポイントを取得します。

    export NGINX_ENDPOINT=$(kubectl get service nginx-demo-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}{":"}{.spec.ports[0].port}')
    echo $NGINX_ENDPOINT
  3. ストレステストツール hey をインストールします。200 の同時接続と合計 50,000 のリクエストで負荷テストを実行します。サンプルのリソース構成に基づくと、単一のレプリカは通常、これを約 1 分で完了します。

    hey -c 200 -n 50000  -disable-keepalive http://$NGINX_ENDPOINT

    同時に、新しいターミナルウィンドウを開き、Deployment のローリングリスタートをトリガーします。

    kubectl rollout restart deployment nginx-deployment-demo
  4. 期待される出力を比較します。

    構成シナリオ

    期待される出力

    ゼロダウンタイム構成なし

    ゼロダウンタイム構成なしのサンプル YAML

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-demo
    spec:
      replicas: 1                 # 本番環境では、高可用性を確保するためにこれを 2 以上に設定します。ここではローリングデプロイの検証を容易にするために 1 に設定しています。
      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
    ---           
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-demo-service
    spec:
      type: LoadBalancer
      selector:
        app: nginx-demo 
      ports:
        - protocol: TCP
          port: 80

    トラフィック損失が観測されます。

    Status code distribution:
      [200]	49644 responses
    
    Error distribution:
      [320]	Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: connection refused
      [18]	Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: no route to host
      [18]	Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: operation timed out

    ゼロダウンタイム構成あり

    ゼロダウンタイムが達成されます。

    Status code distribution:
      [200]	50000 responses

よくある質問

Pod が実行中の状態でスタックし、準備完了にならないのはなぜですか? (Snipaste_2025-11-05_13-57-58)

原因:この動作は通常、startup プローブまたは readiness プローブが失敗していることを示します。

ソリューション

  • プローブ構成の確認:対象の Workload[編集] ページに移動します。ヘルスチェックパス (例:/healthz) とポートがアプリケーションの実際の設定と一致していることを確認します。アプリケーションの起動が遅い場合は、[非正常のしきい値] を増やして、時期尚早の失敗を防ぎます。

    手動検証:一時的にプローブを無効にし、Pod のターミナルにアクセスし、curl などのコマンドを使用して、ヘルスチェックエンドポイントが正しく応答していることを確認します。
  • ログの分析:Pod[イベント][ログ] を確認します。[最後のコンテナー終了のログを表示] オプションを選択して、以前のクラッシュをトラブルシューティングします。

関連ドキュメント