DeploymentによるPodの管理
APIに保存された宣言、Podの所有関係、実際の個数を対応させ、手動削除が台数変更にならない理由を説明します。
説明
Kubernetesでは、アプリを動かす最小の配置単位をPodと呼びます。Deploymentに必要なPod数を宣言すると、ReplicaSetが実際のPod数との差を埋めます。宣言の受付と、Podが利用可能になる時点は別です。
独立したlesson名前空間に、Alpineで待機するPodを2個作ります。所有関係を確認してからPodを1個削除し、別のPodが補充される様子を調べます。最後に宣言を3個へ変え、同じ定義を再適用します。
APIに保存された宣言、Podの所有関係、実際の個数を対応させ、手動削除が台数変更にならない理由を説明します。
1Podを2個保つ定義
replicasは必要なPod数です。selectorは管理対象のラベル、templateは新しく作るPodの定義です。
python3 -c定義ファイルの台数・ラベル・イメージを表示する 'import json; d=json.load(open("deployment.json")); print("replicas=",d["spec"]["replicas"]); print("selector=",d["spec"]["selector"]); print("image=",d["spec"]["template"]["spec"]["containers"][0]["image"])'replicas=2とapp=webのラベルが対応しています。イメージから起動するプロセスはsleepで、終了せず待機します。
2定義をAPIへ登録する
applyでDeploymentを保存します。createdは受付の結果であり、Podの準備完了を意味しません。
kubectl apply -f deployment.jsonファイルの宣言をAPIへ反映するDeployment/webが作成されました。controllerがこの宣言を読み、ReplicaSetとPodを作ります。
3準備完了した個数を確認する
observe.pyはPodのReady条件と再起動回数をAPIから取得します。2個ともReadyになるまで待ちます。
python3 observe.py wait 2 2 0Pod数2・Ready数2になるまで確認するPodは2個、Readyも2個、再起動は0回です。要求した個数と利用可能な個数が一致しました。
4所有関係をたどる
各PodのownerReferencesと、そのReplicaSetのownerReferencesを照合します。名前だけで同じアプリだと推測せず、所有者のUIDを使います。
python3 observe.py ownersUIDでPodからReplicaSetとDeploymentをたどる各PodはReplicaSet、そのReplicaSetはDeployment/webに所有されています。Deploymentが直接Podを数えるだけの構造ではありません。
5変更前の識別子を保存する
後で新しいPodと比較するため、現在のPodのUIDを含むJSONを保存します。
kubectl get pods -l app=web -o json現在のPodをJSONで取得する > before.json
python3 -c保存したPod数を確認する 'import json; print("saved_pods="+str(len(json.load(open("before.json"))["items"])))'2個のPodの記録を保存しました。UIDは同名の資源が再作成されても別の値になります。
6Podを1個削除して補充を待つ
現在の先頭のPodを削除します。Deploymentのreplicasは2のままです。
kubectl delete podPodを1個削除する "$(kubectl get pods -l app=web -o jsonpath='{.items[0].metadata.name}')" --wait=true > /dev/null
python3 observe.py wait 2 2 0必要な2個の準備完了を待つ
python3 observe.py replacement変更前後のUID集合を比較する2個へ戻り、replaced=1になります。削除したPodが復活したのではなく、新しいUIDのPodが作られています。
7必要な個数を3へ変える
継続して3個動かすには、Podを手動で増やすのではなく宣言のreplicasを変更します。
python3 -c宣言のreplicasを3へ変更する 'import json; p="deployment.json"; d=json.load(open(p)); d["spec"]["replicas"]=3; open(p,"w").write(json.dumps(d))'
kubectl apply -f deployment.json変更した宣言を反映する
python3 observe.py wait 3 3 03個の準備完了を確認する宣言と実際のReady数が3になりました。controllerが埋める差の基準を変更したためです。
8同じ定義をもう一度適用する
何も編集せずapplyを繰り返します。
kubectl apply -f deployment.json同じ定義を再適用する
python3 observe.py wait 3 3 0個数が増えていないことを確認するunchangedで、個数も3のままです。同じ宣言を再適用するたびにPodが3個追加される操作ではありません。
まとめ
Podの削除後はReplicaSetが不足分を補充します。
継続する台数はDeploymentのreplicasで指定します。
APIへの受付とPodのReadyを別々に確認します。
操作履歴と解説を振り返れます。
Kubernetes 1.37.0 / kind 0.33.0 / Linux arm64
python3 -c 'import json; d=json.load(open("deployment.json")); print("replicas=",d["spec"]["replicas"]); print("selector=",d["spec"]["selector"]); print("image=",d["spec"]["template"]["spec"]["containers"][0]["image"])'replicas= 2
selector= {'matchLabels': {'app': 'web'}}
image= alpine:3.22kubectl apply -f deployment.jsondeployment.apps/web created
python3 observe.py wait 2 2 0pods=2 ready=2 restarts=0
python3 observe.py ownersPod -> ReplicaSet -> Deployment/web Pod -> ReplicaSet -> Deployment/web
kubectl get pods -l app=web -o json > before.json
python3 -c 'import json; print("saved_pods="+str(len(json.load(open("before.json"))["items"])))'saved_pods=2
kubectl delete pod "$(kubectl get pods -l app=web -o jsonpath='{.items[0].metadata.name}')" --wait=true > /dev/null
python3 observe.py wait 2 2 0
python3 observe.py replacementpods=2 ready=2 restarts=0 old=2 current=2 replaced=1
python3 -c 'import json; p="deployment.json"; d=json.load(open(p)); d["spec"]["replicas"]=3; open(p,"w").write(json.dumps(d))'
kubectl apply -f deployment.json
python3 observe.py wait 3 3 0deployment.apps/web configured pods=3 ready=3 restarts=0
kubectl apply -f deployment.json
python3 observe.py wait 3 3 0deployment.apps/web unchanged pods=3 ready=3 restarts=0
演習完了