🌀

kubectl rollout statusはいつ完了するか

2024/12/11に公開

前提

kubectl rollout restart deployment を実行した際に、.spec.strategy.type==RollingUpdate の場合以下のような挙動になります。

  1. 新規podの起動開始
  2. 新規podの起動完了
  3. 旧podの停止開始
  4. 旧podの停止完了

その進捗を確認できる kubectl rollout status というコマンドがあります。
しかし具体的にどのタイミングで完了になるかが、公式ドキュメントからだと確認できませんでした。

https://kubernetes.io/docs/reference/kubectl/generated/kubectl_rollout/kubectl_rollout_status/#synopsis

By default 'rollout status' will watch the status of the latest rollout until it's done. If you don't want to wait for the rollout to finish then you can use --watch=false. Note that if a new rollout starts in-between, then 'rollout status' will continue watching the latest revision. If you want to pin to a specific revision and abort if it is rolled over by another revision, use --revision=N where N is the revision you need to watch for.

私が運用しているプロダクトは一部 shoryuken を使用しているコンポーネントがあります。
https://github.com/ruby-shoryuken/shoryuken

shoryukenは設定やjobの処理状況により、TERM受信からプロセス停止まで時間がかかるケースが発生します。
https://github.com/ruby-shoryuken/shoryuken/wiki/Signals#term

CI/CDや各種パイプラインを構築する際に、status checkが旧podの停止完了まで待つかどうかがポイントになりました。
そのため実際に動作確認して検証しました。

動作環境

% kubectl version
Client Version: v1.30.5
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.30.2

% sw_vers
ProductName:            macOS
ProductVersion:         15.1.1
BuildVersion:           24B91

動作確認

実際に動かして kubectl rollout statusの振る舞いを確認します。

準備

適当なdeploymentを用意します。
挙動が確認しやすいように、コンテナの起動完了および停止処理にそれぞれ10秒待つようにします。

deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: graceful-shutdown-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: graceful-shutdown-test
  template:
    metadata:
      labels:
        app: graceful-shutdown-test
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: main
        image: busybox
        command: ["/bin/sh"]
        args:
          - -c
          - |
            echo "Starting container, waiting 10 seconds before becoming ready..."
            sleep 10
            echo "Container is now ready"
            
            trap 'echo "Received SIGTERM, sleeping for 10 seconds..."; sleep 10; echo "Exiting..."; exit 0' TERM
            
            while true; do sleep 5; done
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - "[ -f /tmp/ready ]"
          initialDelaySeconds: 5
          periodSeconds: 5
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "sleep 10 && touch /tmp/ready"]

kubectl apply -f deployment.yml でapplyします。

検証

watchコマンドで実際のpodとkubectl rollout statusの結果をチェックしながら作業します。

watch -t "kubectl get po && kubectl rollout status deployment graceful-shutdown-test -w=false"

rollout実行前

NAME                                      READY   STATUS    RESTARTS   AGE
graceful-shutdown-test-59ff466875-6vss2   1/1     Running   0          47m
deployment "graceful-shutdown-test" successfully rolled out

kubectl rollout restart deployment graceful-shutdown-test で rollout実施します。

rollout開始で新規のpodが ContainerCreating になります。
kubectl rollout status はまだ Waiting... となっています。

NAME                                      READY   STATUS              RESTARTS   AGE
graceful-shutdown-test-59ff466875-6vss2   1/1     Running             0          49m
graceful-shutdown-test-85797fc66d-w88nh   0/1     ContainerCreating   0          4s
Waiting for deployment "graceful-shutdown-test" rollout to finish: 1 old replicas are pending termination...

新規のpod (graceful-shutdown-test-85797fc66d-w88nh) が起動完了するとほぼ同時に、旧podが Terminating 状態になります。
この時点で kubectl rollout status は完了状態に切り替わりました。

NAME                                      READY   STATUS        RESTARTS   AGE
graceful-shutdown-test-59ff466875-6vss2   1/1     Terminating   0          49m
graceful-shutdown-test-85797fc66d-w88nh   1/1     Running       0          19s
deployment "graceful-shutdown-test" successfully rolled out

そこから数秒後に旧podの停止も完了しました。
kubectl rollout status の結果は変わらず完了状態です

NAME                                      READY   STATUS    RESTARTS   AGE
graceful-shutdown-test-85797fc66d-w88nh   1/1     Running   0          34s
deployment "graceful-shutdown-test" successfully rolled out

これらの結果から kubectl rollout status は旧podの停止完了まで見届けないことがわかりました。

ちなみに

同じ内容のissueがありました。
そこでも「新podの起動のみ確認し、旧podの状態には依存しない」と回答されています。
https://github.com/kubernetes/kubectl/issues/1628

旧podの停止完了まで確認する必要があれば、 kubectl wait を使うかシェルで確認してねとありました。

kubectl wait --for=delete pod --selector app=graceful-shutdown-test --timeout=180s のような形で 停止完了 (=コンテナ削除) イベントをpollingできそうですが少し考慮事項が多そうです。

Discussion