Certified Kubernetes Application Developer (CKAD) #5 Workloads 1: Deployment、ReplicaSet、ローリングアップデートとロールバック
CKAD 試験で最もよく出くわすリソースが Deployment です。実務でもアプリケーション一式を動かす標準単位が Deployment であり、試験の Application Deployment ドメイン (20%) もここから始まります。Pod を 1 つ直接立ち上げることはほとんどありません。運用環境のアプリはほぼすべて Deployment でデプロイし、バージョンを上げるときはローリングアップデートで無停止に入れ替え、新しいバージョンが問題を起こせば 1 行でロールバックします。
この記事では、Deployment を命令型ですばやく作成する方法から、Deployment の下で ReplicaSet と Pod がどう結びつくのか、そして kubectl rollout でデプロイ履歴を管理し、失敗したバージョンを戻す全工程を、手でなぞって打ち込みながら身につけます。クラスタ動作の全体像がぼんやりしているなら、K8s 実務トラック #4 ワークロード を先に読んでおくと役立ちます。
Deployment を命令型で作成する #
#1 で用意しておいた do alias をそのまま使います。Deployment の骨組みは k create deploy で 1 行で取り出します。
# すぐに作成
k create deploy web --image=nginx:1.25 --replicas=3
# マニフェストの骨組みだけ取り出して編集 (dry-run)
k create deploy web --image=nginx:1.25 --replicas=3 $do > deploy.yaml--replicas フラグがなければ replicas は 1 で作成されます。試験で個数を指定するように言われたら、作成時点で一緒に渡すほうが速いです。生成されたマニフェストは次の形です。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25ここで肝心なのは、selector.matchLabels と template.metadata.labels が 必ず一致 しなければならない点です。selector はこの Deployment がどの Pod を自分のものと見なすかを決める基準であり、template のラベルがその基準に合ってこそ Pod が正常に管理されます。両者が食い違うと、作成そのものが拒否されます。
Deployment、ReplicaSet、Pod の関係 #
Deployment を作ったからといって Deployment が Pod を直接作るわけではありません。その間に ReplicaSet が 1 段挟まっています。
Deployment ──所有──> ReplicaSet ──所有──> Pod (×replicas)- Deployment は「どのバージョンを何個動かすか」を宣言し、バージョンが変わるたびに新しい ReplicaSet を作って入れ替えを指揮します。
- ReplicaSet は「指定された個数の Pod を常に維持する」役割だけを果たします。Pod が死ねば作り直し、多ければ減らします。
- Pod は実際のコンテナが動く最小単位です。
作成直後に実際に何が作られたのかを確認してみます。
k get deploy web
k get rs # web-<ハッシュ> ReplicaSet が 1 つできる
k get pod # web-<rsハッシュ>-<ランダム> Pod が replicas の分だけできるk get rs の出力の名前が web-7d9c8f6b54 のように Deployment 名のうしろにハッシュが付くのが見えます。このハッシュは Pod テンプレートの内容から計算されるので、イメージや環境変数を変えると新しいハッシュの ReplicaSet ができます。この構造こそがローリングアップデートとロールバックの土台です。新しいバージョンを新しい ReplicaSet として作り、古い ReplicaSet は個数を 0 に減らすだけにして履歴として残しておくからです。
スケール: 個数を変える #
Pod の個数を増やしたり減らしたりは k scale で即座に処理します。
# replicas を 5 に
k scale deploy web --replicas=5
# 現在の個数が 3 のときだけ 5 に変更 (条件付き)
k scale deploy web --current-replicas=3 --replicas=5マニフェストを直して k apply する方法もありますが、試験で個数だけ変える作業なら k scale が最も速いです。変更後は k get deploy web の READY 列が 5/5 になるか確認します。
オートスケールが必要な作業なら k autoscale で HorizontalPodAutoscaler を付けます。
k autoscale deploy web --min=2 --max=10 --cpu-percent=70ローリングアップデート: 無停止で新しいバージョンを入れる #
運用中の Deployment のイメージを新しいバージョンに上げるとき、デフォルト戦略は RollingUpdate です。既存の Pod を一度に殺さず、新しい Pod を少しずつ立ち上げながら古い Pod を少しずつ下ろし、サービスが切れないように入れ替えます。
maxSurge と maxUnavailable #
ローリングアップデートの速度と安定性は、2 つの値が決めます。
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 望む個数より最大何個多く立ち上げられるか
maxUnavailable: 1 # 入れ替え中に最大何個まで不足してよいか- maxSurge: アップデート途中に desired replicas を超えて一時的に多く立ち上げられる Pod 数です。値が大きいと新しい Pod をより多く先に立ち上げ、入れ替えが速くなります。
- maxUnavailable: アップデート途中に使用不可状態でも許容される Pod 数です。値が 0 なら新しい Pod が Ready になってからはじめて古い Pod を下ろすので、可用性が最も高くなります。
両方の値とも整数またはパーセンテージ (25%) で与えられます。指定しなければ両方ともデフォルト値 25% です。可用性を最優先にするように言われた作業なら、maxUnavailable: 0 に置くパターンを覚えておきます。
イメージの入れ替えでアップデートをトリガーする #
最もよくあるアップデートは、イメージのバージョンを上げることです。k set image が 1 行で済ませます。
# コンテナ名が nginx のとき v2 に入れ替え
k set image deploy/web nginx=nginx:1.26
# コンテナが複数なら各々を指定
k set image deploy/web nginx=nginx:1.26 sidecar=busybox:1.36set image の nginx= の部分は コンテナ名 であってイメージ名ではありません。コンテナ名が紛らわしければ、k get deploy web -o jsonpath='{.spec.template.spec.containers[*].name}' で先に確認します。
イメージだけでなく他のフィールドまで変えなければならないなら、k edit でマニフェストを直接直します。
k edit deploy webk edit で template の中の何かを変えると新しい ReplicaSet ができ、ローリングアップデートが始まります。逆に k scale のように template の外 (replicas) だけを変えると、新しい ReplicaSet はできません。つまり 新しい revision は Pod テンプレートが変わったときだけ 作られます。
rollout でデプロイを管理する #
アップデートがうまく進んでいるか、履歴がどう積み上がるか、問題が起きたらどう戻すかを、すべて kubectl rollout が担当します。CKAD で最も手に馴染ませるべきコマンド群です。
進行状態の確認 #
# ローリングアップデートが終わるまで進行状況を見せる
k rollout status deploy/webset image の直後にこのコマンドをかけておけば、「全部 Ready になったか」を待ってから確認できます。作業が完了したかを採点前に自分で検証する用途に便利です。
履歴の確認 #
# revision の一覧
k rollout history deploy/web
# 特定の revision の詳細 (その時点のテンプレート)
k rollout history deploy/web --revision=2revision は 1 から上がっていきます。どの変更がどの revision だったかメモ (CHANGE-CAUSE) を残したければ、変更時に --record を付けるか、kubernetes.io/change-cause アノテーションを直接付けます。
k annotate deploy web kubernetes.io/change-cause="update to nginx:1.26"一時停止と再開 #
複数の変更を一度にまとめて 1 回のロールアウトで処理したいときは、pause で止めておいて何度か修正したあと resume します。
k rollout pause deploy/web
k set image deploy/web nginx=nginx:1.26
k set resources deploy/web -c=nginx --limits=cpu=200m,memory=256Mi
k rollout resume deploy/web # このとき一度にロールアウトpause 状態では template を変えても新しい Pod は立ち上がりません。resume する瞬間、累積した変更が 1 つの revision として反映されます。canary のような戦略の土台であり、詳しいデプロイ戦略は #8 で扱います。
保管する履歴の個数 #
古い ReplicaSet を何個まで残すかは revisionHistoryLimit が決めます。デフォルト値は 10 で、0 に置くとロールバックする履歴が消えるので注意します。
spec:
revisionHistoryLimit: 5ロールバックシナリオの実習 #
ここからは、試験によく出る流れを最初から最後まで打ち込みます。正常なバージョンを動かしていて、誤ったバージョンをデプロイして失敗を検知し、直前のバージョンに戻すシナリオです。
# 1) 正常なバージョンをデプロイ (revision 1)
k create deploy web --image=nginx:1.25 --replicas=3
k rollout status deploy/web
# 2) 誤ったイメージでアップデート (revision 2)、存在しないタグ
k set image deploy/web nginx=nginx:does-not-exist
# 3) 失敗の検知
k rollout status deploy/web # 進行が止まって終わらない
k get pod # 新しい Pod が ImagePullBackoff 状態誤ったイメージなので新しい Pod はイメージを受け取れず ImagePullBackOff に陥ります。ここで重要なのは、maxUnavailable が 25% なので古い Pod の一部はまだ生きていてサービスが完全には死なない点です。RollingUpdate が可用性を守ってくれるおかげです。それでも新しいバージョンが壊れたので戻します。
# 4) 直前の revision にロールバック
k rollout undo deploy/web
k rollout status deploy/web # 再び正常に収束
# 5) 確認: 再び 1.25 に戻ったか
k get deploy web -o jsonpath='{.spec.template.spec.containers[0].image}'特定の revision をピンポイントで戻すこともできます。
# revision の一覧を見て
k rollout history deploy/web
# 3 番目の revision に戻す
k rollout undo deploy/web --to-revision=3undo は古い ReplicaSet の個数を再び上げ、壊れた ReplicaSet の個数を 0 に下げる方式で動作します。だからロールバックが速く、戻した結果がもう 1 つの新しい revision として記録されます。revision 番号は消えずに積み上がり続ける点を覚えておきます。
RollingUpdate と Recreate #
Deployment の戦略には RollingUpdate のほかに Recreate もあります。Recreate は既存の Pod を全部下ろしてから新しい Pod を立ち上げるので、入れ替え中にサービスが一瞬切れます。同時に 2 つのバージョンが立っていてはいけないアプリ (例: 単一書き込みデータベースのマイグレーション) に使います。
spec:
strategy:
type: Recreateデフォルトは無停止の入れ替えである RollingUpdate であり、Recreate はダウンタイムを許容する特殊な状況用です。2 つの戦略のトレードオフと、blue-green・canary のような無停止の上級戦略は #8 Deployment 戦略 で詳しく扱います。
試験のポイント #
- Deployment の作成 は
k create deploy <name> --image=<img> --replicas=Nが最も速いです。--replicas省略時は 1 です。 - selector.matchLabels と template.labels は一致 しなければなりません。食い違うと作成が拒否されます。
- 所有関係は Deployment → ReplicaSet → Pod です。新しい revision は Pod テンプレートが変わったときだけできます。replicas だけ変えても新しい ReplicaSet はできません。
- スケールは
k scale deploy <name> --replicas=Nです。 - イメージの入れ替えは
k set image deploy/<name> <コンテナ名>=<img>です。等号の左はイメージではなくコンテナ名です。 - maxSurge は超過許容数、maxUnavailable は不足許容数 です。デフォルト値は両方とも 25% で、可用性最優先なら
maxUnavailable: 0です。 - rollout コマンド群:
status(進行)、history(履歴)、history --revision=N(詳細)、undo(直前へロールバック)、undo --to-revision=N(特定バージョン)、pause・resume(まとめてデプロイ) を手に馴染ませておきます。 - ロールバック後も revision は積み上がります。保管個数は
revisionHistoryLimit(デフォルト 10) が決めます。
まとめ #
この記事でつかんだもの。
- Deployment はアプリデプロイの標準単位 であり、Deployment → ReplicaSet → Pod の 3 段構造で動作します。
- 作成・スケールは
k create deploy・k scaleで命令型にすばやく処理します。 - ローリングアップデート は maxSurge・maxUnavailable で速度と可用性を調節し、
k set imageやk editがトリガーします。 kubectl rolloutでデプロイ状態を追跡して履歴を管理し、undoで失敗したバージョンを 1 行で戻します。- Recreate はダウンタイムを許容する特殊な状況用で、デフォルトは無停止の RollingUpdate です。
次: Workloads 2 #
Deployment でステートレスなアプリを無停止に動かす方法をつかみました。ところが、すべてのワークロードが「どのノードでも N 個立ち上げればよい」形なわけではありません。
#6 Workloads 2: DaemonSet、StatefulSet では、すべてのノードに正確に 1 つずつ Pod を入れなければならない DaemonSet (ログ収集機・モニタリングエージェント)、そして安定したネットワーク識別子と順序が保証されたストレージが必要な StatefulSet (データベース・メッセージキュー) を扱います。Deployment と何が違い、試験でどのような形で出るのかを、自分で作ってみながら整理します。