ヘルスチェックとローリングアップデート
検査失敗後のReady、再起動回数、新旧Pod数から、更新が止まる理由を説明します。
説明
readinessは要求を受けられる状態か、livenessはコンテナを再起動すべき状態かを判定します。同じ検査に見えても、失敗した後の処理は異なります。Deploymentの更新では、ReadyなPod数も旧版を減らす条件になります。
1個のPodで、準備完了を表すファイルと生存を表すファイルを別に用意します。それぞれを消して状態と再起動回数を確認した後、Readyにならない版へ更新して旧版が残ることを調べます。
検査失敗後のReady、再起動回数、新旧Pod数から、更新が止まる理由を説明します。
11個のPodと検査を用意する
readinessは/tmp/ready、livenessは/tmp/healthyの存在を検査します。起動時に両方を作る定義です。
python3 -c1個のPodと二つの検査設定を用意する 'import json; p="deployment.json"; d=json.load(open(p)); d["spec"]["replicas"]=1; open(p,"w").write(json.dumps(d)); c=d["spec"]["template"]["spec"]["containers"][0]; print(json.dumps({k:c[k] for k in ["readinessProbe","livenessProbe"]},sort_keys=True))'
kubectl apply -f deployment.json検査付きのDeploymentを作る
python3 observe.py wait 1 1 0初期状態を確認する1個がReadyになりました。readinessは1回の失敗、livenessは2回続けて失敗した場合にそれぞれの処理へ進む設定です。
2readinessだけを失敗させる
/tmp/readyを消します。プロセスと/tmp/healthyはそのままです。
kubectl exec deployment/web -- rm /tmp/ready準備完了の条件だけを失わせる
python3 observe.py wait 1 0 0Readyと再起動回数を読むPodは1個のまま、Readyは0、再起動も0です。readinessの失敗だけではコンテナは再起動しません。
3準備完了へ戻す
同じコンテナ内にファイルを戻します。
kubectl exec deployment/web -- touch /tmp/ready準備完了の条件を戻す
python3 observe.py wait 1 1 0再起動なしで復帰したことを読む再起動せずReadyへ戻りました。起動し直すことと、要求を受けられる状態になることは別です。
4livenessを失敗させる
/tmp/healthyを消し、再起動を待ちます。起動コマンドが両方のファイルを作り直します。
kubectl exec deployment/web -- rm /tmp/healthy生存検査を失敗させる
python3 observe.py wait 1 1 1再起動1回とReadyへの復帰を待つ再起動回数が1になり、Readyへ戻りました。Podを別に作ったのではなく、同じPod内のコンテナが再起動しています。
5更新時の台数条件
maxSurge=1は必要数を超えて追加できる個数、maxUnavailable=0は更新中に許す利用不能数です。
python3 observe.py budget更新設定と必要数を表示する必要数1に対し、新版を追加して最大2個にできます。利用可能数を1未満に減らす更新は許していません。
6Readyにならない版へ更新する
VERSION=badでは起動時に/tmp/readyを作りません。Podテンプレートを変更するため、新しいReplicaSetが作られます。
kubectl set env deployment/web VERSION=bad準備完了にならない版へ更新する
python3 observe.py wait 2 1 1旧版と新版の合計数・Readyを確認するPodは2個でもReadyは1個です。新版がReadyにならないため、旧版が残っています。Pod数だけを見て更新成功と判断できません。
7準備完了になる版へ直す
VERSION=v2へ変更すると、新しいPodは/tmp/readyを作ります。
kubectl set env deployment/web VERSION=v2起動条件を修正した版へ更新する
python3 observe.py wait 1 1 0更新後の必要数とReadyを確認する更新後はPod1個・Ready1個へ戻ります。新しいPodの再起動回数は0で、旧Podの再起動回数を引き継ぐ値ではありません。
8最終的に動く版
Deploymentの宣言と、実際のコンテナ内の環境変数を照合します。
kubectl get deployment web宣言の版を読む -o jsonpath='{.spec.template.spec.containers[0].env[0].value}{"\n"}'
kubectl exec deployment/web -- printenv VERSION実行中の版を読む両方v2です。宣言だけでなく、実際に動くコンテナまで更新が反映されています。
まとめ
readiness失敗はReadyを下げ、liveness失敗は再起動につながります。
更新中は総Pod数とReady数を別々に確認します。
新版がReadyにならない場合、更新条件により旧版が残ります。
操作履歴と解説を振り返れます。
Kubernetes 1.37.0 / kind 0.33.0 / Linux arm64
python3 -c 'import json; p="deployment.json"; d=json.load(open(p)); d["spec"]["replicas"]=1; open(p,"w").write(json.dumps(d)); c=d["spec"]["template"]["spec"]["containers"][0]; print(json.dumps({k:c[k] for k in ["readinessProbe","livenessProbe"]},sort_keys=True))'
kubectl apply -f deployment.json
python3 observe.py wait 1 1 0{"livenessProbe": {"exec": {"command": ["test", "-f", "/tmp/healthy"]}, "failureThreshold": 2, "periodSeconds": 1}, "readinessProbe": {"exec": {"command": ["test", "-f", "/tmp/ready"]}, "failureThreshold": 1, "periodSeconds": 1}}
deployment.apps/web created
pods=1 ready=1 restarts=0kubectl exec deployment/web -- rm /tmp/ready
python3 observe.py wait 1 0 0pods=1 ready=0 restarts=0
kubectl exec deployment/web -- touch /tmp/ready
python3 observe.py wait 1 1 0pods=1 ready=1 restarts=0
kubectl exec deployment/web -- rm /tmp/healthy
python3 observe.py wait 1 1 1pods=1 ready=1 restarts=1
python3 observe.py budget{"maxSurge": 1, "maxUnavailable": 0}
desired=1kubectl set env deployment/web VERSION=bad
python3 observe.py wait 2 1 1deployment.apps/web env updated pods=2 ready=1 restarts=1
kubectl set env deployment/web VERSION=v2
python3 observe.py wait 1 1 0deployment.apps/web env updated pods=1 ready=1 restarts=0
kubectl get deployment web -o jsonpath='{.spec.template.spec.containers[0].env[0].value}{"\n"}'
kubectl exec deployment/web -- printenv VERSIONv2 v2
演習完了