Web ターミナルを開いて、nginx を動かしてみましょう。 起動できたら数を増やし、そのうち 1 つの Pod を削除して、代わりが作られる様子を見ます。
続いて、アプリを更新し、前のバージョンへ戻します。 自分専用の実習環境で、ここまで学んだ「希望する状態を書き、Kubernetes がそれに近づける」という動きを確かめる章です。
GOAL この章のゴール
- アプリを起動し、Pod の数を増減できる
- Pod を削除して、代わりが作られることを確認できる
- アプリを更新し、前のバージョンへ戻せる
1. 眺める
まず、何も作っていない状態のクラスタを見ます。
kubectl get nodes -o wide
kubectl get pods -A出力例
NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE
tenant-control-plane-7k2qd Ready control-plane 1h v1.37.1 10.0.1.10 Ubuntu 26.04.1 LTS
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system cilium-xxxxx 1/1 Running 0 1h
kube-system cilium-operator-xxxxxxxxxx-xxxxx 1/1 Running 0 1h
kube-system coredns-xxxxxxxxxx-xxxxx 1/1 Running 0 1h
kube-system etcd-tenant-control-plane-7k2qd 1/1 Running 0 1h
kube-system kube-apiserver-tenant-control-plane-7k2qd 1/1 Running 0 1h
kube-system kube-controller-manager-tenant-control-plane-7k2qd 1/1 Running 0 1h
kube-system kube-scheduler-tenant-control-plane-7k2qd 1/1 Running 0 1hkube-system に、5 章で並べた登場人物が Pod として居ます。
etcd、kube-apiserver、kube-controller-manager、kube-scheduler は kubeadm が static Pod として置いたものです。
Kubernetes のドキュメントによると、static Pod は「API サーバーが関知しないまま、特定のノードの kubelet が直接管理する Pod」で、kubelet は「static Pod ごとに API サーバー上にミラー Pod を作るので、API サーバーからは見えるが、API サーバーから操作はできない」ものです。
Cilium は Pod をネットワークにつなぐプログラムで、CoreDNS はクラスタ内の名前解決を行う DNS サーバーです。
kube-proxy の Pod は無く、cloud-controller-manager も管理クラスタ側に居るのでここには出ません。
2. 作る
nginx の Deployment を作ります。 YAML は heredoc でそのまま流します。
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels: { app: web }
spec:
replicas: 2
selector:
matchLabels: { app: web }
template:
metadata:
labels: { app: web }
spec:
containers:
- name: nginx
image: nginx:1.29.0
ports:
- containerPort: 80
EOF
kubectl rollout status deployment/web --timeout=180s
kubectl get deployment,replicaset,pods -l app=web出力例
deployment.apps/web created
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 2/2 2 2 5s
NAME DESIRED CURRENT READY AGE
replicaset.apps/web-7c9d8f6b5 2 2 2 5s
NAME READY STATUS RESTARTS AGE
pod/web-7c9d8f6b5-abcde 1/1 Running 0 5s
pod/web-7c9d8f6b5-fghij 1/1 Running 0 5sDeployment を 1 つ書くと、ReplicaSet が 1 つ、その配下に Pod が 2 つできています。
6 章の入れ子がそのまま出ています。
Pod 名の 7c9d8f6b5 は ReplicaSet 名の末尾と同じで、template のハッシュです。
3. 増やす
replicas を 4 にします。
YAML を書き換えて apply し直してもよいですが、ここでは scale を使います。
kubectl scale deployment web --replicas=4
kubectl get pods -l app=web出力例
deployment.apps/web scaled
NAME READY STATUS RESTARTS AGE
web-7c9d8f6b5-abcde 1/1 Running 0 1m
web-7c9d8f6b5-fghij 1/1 Running 0 1m
web-7c9d8f6b5-klmno 0/1 ContainerCreating 0 1s
web-7c9d8f6b5-pqrst 0/1 ContainerCreating 0 1sscale がやったのは Deployment の spec.replicas を 4 に書き換えることだけです。
Deployment controller がそれを ReplicaSet に伝え、ReplicaSet controller が「2 足りない」を見て 2 つ作りました。
kubectl get pods -o wide で、それぞれが配置されたノードも確認できます。
4. 壊す
本題です。 Pod を 1 つ消して、戻ってくるのを見ます。
先にシミュレータでもう一度動きを確認しておきます。 「Pod を kill」を押すと、少し遅れて controller が作り直します。
- web-00000Running
- web-00001Running
- web-00002Running
- controller: 監視を開始しました
controller を止めると、kill した Pod は戻ってきません。これが「宣言した状態を誰かが見張り続ける」ことの意味です。
実機では kubectl get pods -w で変化を追います。
-w は変化があるたびに行を出し、Ctrl-C まで止まりません。
先に delete を投げてから -w を始めると、Terminating と新しい Pod の作成が順に流れます。
kubectl delete pod $(kubectl get pod -l app=web -o jsonpath='{.items[0].metadata.name}') --wait=false
kubectl get pods -l app=web -w出力例
pod "web-7c9d8f6b5-abcde" deleted
NAME READY STATUS RESTARTS AGE
web-7c9d8f6b5-abcde 1/1 Terminating 0 3m
web-7c9d8f6b5-fghij 1/1 Running 0 3m
web-7c9d8f6b5-klmno 1/1 Running 0 2m
web-7c9d8f6b5-pqrst 1/1 Running 0 2m
web-7c9d8f6b5-uvwxy 0/1 Pending 0 0s
web-7c9d8f6b5-uvwxy 0/1 ContainerCreating 0 0s
web-7c9d8f6b5-uvwxy 1/1 Running 0 2s
web-7c9d8f6b5-abcde 0/1 Terminating 0 3m名前が 1 つ変わって、数は 4 のまま。
Deployment にも ReplicaSet にも触っていません。
ReplicaSet controller が replicas: 4 と「Terminating を除いた Pod の数 3」の差分を見て、1 つ作っただけです。
誰が消したかは関係ありません。
手で Pod を消した場合や、ノード障害で Pod が削除された場合に、この仕組みで数を補います。
Pod が残ったままコンテナだけが OOM kill された場合は、kubelet がコンテナを再起動します。
Ctrl-C で watch を抜けてから、次に進んでください。
5. 調べる
describe は、1 つのオブジェクトについて spec、status、関連する Events をまとめて出します。
何かがおかしいとき、最初に見るのはここです。
POD=$(kubectl get pod -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl describe pod "$POD"
kubectl events --for "pod/$POD"出力例
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m default-scheduler Successfully assigned default/web-7c9d8f6b5-uvwxy to tenant-control-plane-7k2qd
Normal Pulled 2m kubelet Container image "nginx:1.29.0" already present on machine
Normal Created 2m kubelet Created container: nginx
Normal Started 2m kubelet Started container nginxEvents の From 列に注目してください。
default-scheduler がノードを決め、kubelet がイメージを確認してコンテナを作り、起動しています。
5 章のシーケンス図の後半が、そのままログになっています。
Pulled が “already present” なのは、先に作った Pod で pull 済みだからです。
Deployment 側も見ておきます。
kubectl describe deployment web | grep -A3 -E '^Replicas|^StrategyType|^RollingUpdateStrategy|^NewReplicaSet'出力例
Replicas: 4 desired | 4 updated | 4 total | 4 available | 0 unavailable
StrategyType: RollingUpdate
RollingUpdateStrategy: 25% max unavailable, 25% max surge
NewReplicaSet: web-7c9d8f6b5 (4/4 replicas created)6. 更新する
イメージを変えて、ローリングアップデートを走らせます。
6 章のシミュレータで見た maxSurge / maxUnavailable が既定の 25% で効きます。
kubectl set image deployment/web nginx=nginx:1.29.1
kubectl rollout status deployment/web
kubectl get replicasets -l app=web出力例
deployment.apps/web image updated
Waiting for deployment "web" rollout to finish: 1 out of 4 new replicas have been updated...
Waiting for deployment "web" rollout to finish: 2 out of 4 new replicas have been updated...
Waiting for deployment "web" rollout to finish: 1 old replicas are pending termination...
deployment "web" successfully rolled out
NAME DESIRED CURRENT READY AGE
web-5d4c7b8f9 4 4 4 30s
web-7c9d8f6b5 0 0 0 8m新しい ReplicaSet が 4、古い ReplicaSet が 0 で残っています。 Pod 名のハッシュも変わっているはずです。
7. 戻す
履歴を見て、1 つ前に戻します。
kubectl rollout history deployment/web
kubectl rollout undo deployment/web
kubectl rollout status deployment/web
kubectl get replicasets -l app=web
kubectl rollout history deployment/web出力例
deployment.apps/web
REVISION CHANGE-CAUSE
1 <none>
2 <none>
deployment.apps/web rolled back
deployment "web" successfully rolled out
NAME DESIRED CURRENT READY AGE
web-5d4c7b8f9 0 0 0 2m
web-7c9d8f6b5 4 4 4 10m
deployment.apps/web
REVISION CHANGE-CAUSE
2 <none>
3 <none>undo は、nginx:1.29.0 の template を持つ古い ReplicaSet (7c9d8f6b5) を 4 に伸ばし、新しい方を 0 に縮めました。
ReplicaSet の一覧が 2 行のまま変わっていないことから、新しい ReplicaSet は作られていないと分かります。
履歴では revision 1 が 3 に昇格しています。
rollout undo --to-revision=N で任意の世代にも戻せます。
後片付け
kubectl delete deployment web
kubectl wait --for=delete pod -l app=web --timeout=180s
kubectl get pods -l app=web出力例
deployment.apps "web" deleted
No resources found in default namespace.Deployment を消すと、ReplicaSet と Pod も消えます。
子は親の ownerReferences を持っていて、Kubernetes のドキュメントの言葉では「既定ではバックグラウンドのカスケード削除が使われ、API サーバーは親オブジェクトを即座に消し、garbage collector controller が依存するオブジェクトをバックグラウンドで片付ける」からです。
これも controller の 1 つです。
Part 1 のまとめ
- コンテナは、層になったイメージ、namespace、pivot_root、cgroups を揃えて起動した、ただのプロセス (1 章)。
- Docker は作って配って動かすを 1 本にしたが、頼む相手は 1 台のホストの Docker だけ (2 章)。
- 部品は 2008 年に揃い、Docker は 2013 年、Kubernetes は 2014 年に出て、1.0 と同時に CNCF に移った (3 章)。
- マニフェストを apiserver に預けると etcd に記録され、spec と status の 2 つの欄で望みと現実を分けて持つ (4 章)。
- controller が spec と現在の状態の差分を埋め続け、scheduler が置き場所を決め、kubelet がノードでコンテナを起動する。dockershim は 2022 年に消えた (5 章)。
- Deployment → ReplicaSet → Pod。Service が名前を与え、ConfigMap と Secret が可変部分を差す (6 章)。
- 3 つの顔があり、SIG が作り、CRD で拡張できる (7 章)。
- そして今、Pod を消しても戻ることを自分の目で見た (この章)。
Part 2 からは、この Pod の「中」と「間」に入っていきます。
ふりかえり
Qkubectl scale deployment web --replicas=4 が直接書き換えるのは?
scale は Deployment の spec.replicas を変えるだけです。ReplicaSet への反映は Deployment controller、Pod の作成は ReplicaSet controller が行います。
QPod を消したあと、戻ってこないものは?
戻るのは数です。新しい Pod は新しい名前、新しい IP、空の書き込み層で起動します。
Qrollout undo が行うことは?
undo は古い ReplicaSet を再利用します。履歴として残っている ReplicaSet があるから戻せます。revisionHistoryLimit を 0 にすると戻せなくなります。
参考
- Kubernetes ドキュメント「Deployments」(scale、rollout、undo、change-cause): https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- Kubernetes ドキュメント「Pods」: https://kubernetes.io/docs/concepts/workloads/pods/
- Kubernetes ドキュメント「Kubernetes Components」: https://kubernetes.io/docs/concepts/overview/components/
- Kubernetes ドキュメント「Create static Pods」: https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/
- Kubernetes ドキュメント「Garbage Collection」(ownerReferences、カスケード削除): https://kubernetes.io/docs/concepts/architecture/garbage-collection/
- Kubernetes チュートリアル「Kubernetes Basics」(Deploy / Explore / Scale / Update): https://kubernetes.io/docs/tutorials/kubernetes-basics/
読み切ると称号を獲得
「あるべき状態」の執行者
この Part を読み切りました。
称号一覧