Container Service for Kubernetes (ACK) クラスター内のアプリケーションをサービス中断なしで更新するには、readiness プローブ、readinessGates、preStop フック、および Server Load Balancer (SLB) の接続ドレインを使用して Deployment を設定します。この構成により、スムーズなトラフィック移行と継続的な高可用性が実現します。
仕組み
サービスのアップグレード中に高可用性を確保するために、ステートレスアプリケーション (Deployment) にはローリングアップデート戦略を使用できます。この戦略では、Pod を 1 つずつ置き換えることで、受信トラフィックに対する Pod の継続的な可用性を確保します。コアプロセスは、以下のフェーズに分かれています。
起動フェーズ:まず、新しいバージョン (v2) の Pod が作成されます。Kubernetes は、新しい Pod が readiness プローブに合格し、リクエストを処理できることを確認するまで待機します。それまでは、Pod は Service からのトラフィックを受信しません。
トラフィック移行フェーズ:
readinessGatesが有効化されると、新しいポッドはまず readiness チェックに合格する必要があります。その後、その IP は関連付けられたサービスのエンドポイントに登録され、ロードバランサー (SLB) のバックエンドサーバーグループと同期されて、トラフィックの受信を開始します。続いて、システムは旧バージョン (v1) のポッドに終了シグナルを送信し、エンドポイントからその IP を削除することで、新しいリクエストを受信しないようにします。詳細については、「readinessGates の仕組み」をご参照ください。
グレースフルシャットダウンフェーズ: 古い Pod は削除される前に、事前定義された preStop フックを実行し、終了猶予期間 (
terminationGracePeriodSeconds) を使用して確立された接続の処理を完了する一方、SLB は処理中のリクエストに対して接続ドレインを実行します。このプロセスにより、すべての進行中のリクエストが確実に完了し、ダウンタイムなしのローリングアップデートが実現します。
前提条件
クラスターのバージョンは 1.24 以降である必要があります。詳細については、「クラスターのアップグレード」をご参照ください。
cloud-controller-manager コンポーネントは v2.10.0 以降です。詳細については、「Cloud Controller Manager」をご参照ください。
サンプルアプリケーションのデプロイ
次の例では、ステートレスな NGINX アプリケーションをデプロイする方法を説明します。
コンソール
ACK クラスター ページで、対象クラスターの名前をクリックします。左側のナビゲーションウィンドウで、 の順にクリックします。
展開 ページで、YAML のリソースの作成 をクリックします。次の内容をテンプレートエディターにコピーし、デプロイ をクリックします。
ポップアップウィンドウで、対象のステートレスアプリケーションを見つけ、ビュー をクリックし、Pod のステータスが
Runningであることを確認します。
kubectl
次の YAML 内容を 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 # 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 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 は準備未完了とマークされます。 # --- 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: # 接続ドレインのタイムアウト。この値は、アプリケーションの preStop ロジックと一致させる必要があります。範囲:10-900。 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout: "30" # 接続ドレインを有効にします。 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain: "on" spec: type: LoadBalancer selector: app: nginx-demo ports: - protocol: TCP port: 80NGINX アプリケーションをデプロイし、Service を作成します。
kubectl apply -f nginx-demo.yaml対象のアプリケーション Pod が
Running状態であることを確認します。kubectl get pod | grep nginx-deployment-demo
Pod の readiness チェック
startupProbe(起動プローブ):Java アプリケーションなどの起動が遅いアプリケーションが起動を完了したかどうかをチェックします。起動プローブが成功するまで、readiness プローブと liveness プローブは実行されません。これにより、Kubelet が起動の遅さを障害と誤判断してコンテナを再起動するのを防ぎます。readinessProbe(readiness プローブ):コンテナが外部リクエストを処理する準備ができているかどうかを判断します。readiness チェックが成功すると、Pod の IP アドレスが関連するすべての Service の Endpoints に追加されます。これは、Pod がトラフィックを受け入れられることを示します。readinessGates:readinessProbeに加えて、readinessGatesも準備完了ステータスを示した場合にのみ、Pod はトラフィックを受け入れる準備が完全に整ったと見なされます。
グレースフルシャットダウン
アプリケーションのグレースフルシャットダウン
preStop:コンテナが終了する前に実行されるフックコマンドです。アプリケーションのグレースフルシャットダウン用のコマンドを設定して、すべての処理中のリクエストが処理されるようにします。これにより、サービスが中断なくシャットダウンされることが保証されます。必要に応じてカスタムフックメソッドを設定してください。sleep コマンドのみを使用すると、グレースフルシャットダウンプロセスが正しく終了しない可能性があります。
terminationGracePeriodSeconds:Pod が終了対象としてマークされてからSIGKILLシグナルで強制的に終了されるまでの合計時間です。デフォルトは 30 秒です。この値は、preStopフックの実行時間とコンテナ自体のクリーンアップ時間の合計をカバーするのに十分な長さでなければなりません。
SLB 接続ドレイン
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drainアノテーション:Server Load Balancer (SLB) の接続ドレイン機能を有効にします。service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout:接続ドレインのタイムアウト期間 (秒単位) です。この値は、preStop フックで処理中のリクエストを処理するために必要な時間に近い値を設定することを推奨します。
ローリングアップデート戦略
strategy:Deployment のデフォルトの更新戦略は RollingUpdate です。この戦略は、段階的な置換方式を使用します。新しい Pod を徐々に作成し、新しい Pod の準備ができた後に対応する古い Pod を削除します。これにより、更新プロセス中のサービス可用性が確保されます。maxUnavailable:ローリングアップデート中に利用できなくなる Pod レプリカの最大数です。デフォルト値は 25% です。絶対数を指定することもできます。maxSurge:ローリングアップデート中に、希望するレプリカ数を超えて作成できる Pod の最大数です。値が大きいほど更新は速くなりますが、より多くのリソースを消費します。デフォルト値は 25% です。絶対数を指定することもできます。
ゼロダウンタイムローリングデプロイの検証
サンプルアプリケーションのアクセス URL を取得します。
export NGINX_ENDPOINT=$(kubectl get service nginx-demo-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}{":"}{.spec.ports[0].port}') echo $NGINX_ENDPOINT負荷テストツール hey をインストールします。200 の同時接続と合計 50,000 のリクエストで負荷テストを実行します。この例のリソース構成では、単一のレプリカでテストが約 1 分で完了するはずです。
hey -c 200 -n 50000 -disable-keepalive http://$NGINX_ENDPOINTテストの実行中に、新しいターミナルウィンドウを開き、すぐに Deployment を再起動します。
kubectl rollout restart deployment nginx-deployment-demo次の表に、期待される出力を示します。
デプロイシナリオ
期待される出力
ゼロダウンタイム構成なし
トラフィック損失が観測されます。
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 のステータス:Running だが Not Ready
原因:この問題は通常、起動プローブまたは readiness プローブの失敗が原因で発生します。
解決策:
-
Readiness プローブの設定:対象の ワークロード の 編集 ページで、ヘルスチェックのリクエストパス (例:/healthz) とポートがアプリケーションが提供するものと一致していることを確認します。アプリケーションの起動時間が長い場合は、異常のしきい値 を増やして、早すぎる失敗を回避します。
一時的に レディチェック を無効にし、Pod のターミナルまたはそのホストにログインし、
curlなどのコマンドを使用して、ヘルスチェックメソッドが正しく応答することを確認できます。 -
アプリケーションの問題のトラブルシューティング:Pod の イベント と ログ を確認して問題を調査します。最後のコンテナーが終了した時のログを表示する を選択します。