シリーズ記事一覧
- 第1回:全体像と環境構築
- 第2回:Pod・ReplicaSet・Deployment
- 第3回:Service・Ingress
- 第4回:ConfigMap・Secret・PersistentVolume
- 第5回:模擬プロジェクト(Web+API+DB+Redis)
- 第6回:トラブルシュートと運用
- 第7回:総まとめと次のステップ
📑 目次
- この記事について
- この記事のゴール
- 前提条件
- Podとは?
- ReplicaSetとは?
- Deploymentとは?
- Deployment YAMLの書き方
- ハンズオン:Deploymentを操作する
- まとめ
1. この記事について
1-1. シリーズ概要
Docker Compose経験者が「素のKubernetes」を
1週間で実践レベルまで習得することを目指す学習記録です。
1-2. シリーズ構成
| 回 | テーマ | 内容 |
|---|---|---|
| 第1回 | 全体像と環境構築 | Docker Composeとの対比、minikube導入 |
| 第2回(本記事) | Pod と Deployment | コンテナ起動〜スケーリング〜ローリングアップデート |
| 第3回 | Service と Ingress | ネットワークと外部公開 |
| 第4回 | ConfigMap / Secret / PV | 設定管理と永続化 |
| 第5回 | 模擬プロジェクト | 全概念を組み合わせて実践 |
| 第6回 | トラブルシュートと運用 | エラー対応、ログ確認 |
| 第7回 | 総まとめ | 振り返り |
1-3. 対象読者
- 第1回を読み終えた方(k8sの全体像・minikube環境構築済み)
- Docker Composeの
servicesやscaleを使ったことがある方 - 「Podって何?Deploymentとの違いは?」が曖昧な方
2. この記事のゴール
| # | ゴール | チェック |
|---|---|---|
| ① | Pod・ReplicaSet・Deploymentの3層構造を説明できる | 各層の役割と関係を言語化 |
| ② | ローリングアップデートの仕組みを説明できる | maxSurge/maxUnavailableの動きを図示 |
| ③ | ロールバックの履歴管理を理解している | revision番号の振り直しを説明できる |
| ④ | Deployment YAMLを読み書きできる | DockerComposeとの対比で各フィールドを説明 |
| ⑤ | labels/selectorの仕組みを説明できる | なぜ必要か、どこで使われるかを語れる |
3. 前提条件
3-1. 環境情報
| 項目 | バージョン / 詳細 |
|---|---|
| OS | Windows 11 + WSL2 Ubuntu |
| minikube | インストール済み(第1回で構築) |
| kubectl | インストール済み(第1回で構築) |
3-2. 前提知識
- 第1回の内容(k8sの全体像、各コンポーネントの役割)
- Docker Composeの
servicesimageportsscaleの意味
4. Podとは?
4-1. 一言で言うと
Podはk8sでコンテナを動かす最小単位です。
| 観点 | Docker Compose | k8s |
|---|---|---|
| 最小単位 | コンテナ(container) | Pod |
| 定義場所 |
services: の中 |
Pod用のYAML |
| 1つの中身 | 1コンテナ | 1つ以上のコンテナ(通常は1つ) |
4-2. 🍽️飲食チェーンで例えると
🍽️ コンテナ = 料理人、Pod = 調理台
- 基本は1つの調理台に1人の料理人(1 Pod = 1コンテナ)
- まれに、2人で1つの調理台を共有することもある(サイドカーパターン)
- 例:メインの料理人 + 横で盛り付け専門の人
- 調理台(Pod)が壊れたら、料理人(コンテナ)も一緒にいなくなる
4-3. なぜ「コンテナ」ではなく「Pod」?
| 疑問 | 答え |
|---|---|
| なぜコンテナを直接管理しない? | 複数コンテナをセットで扱いたいケースがあるから |
| 具体的にどんなケース? | メインアプリ + ログ収集コンテナ、 メインアプリ + プロキシ等 |
| でも普段は? |
99%のケースで1 Pod = 1コンテナ。 まずはこれで覚えてOK |
4-4. Podの重要な特性
| 特性 | 意味 | 影響 |
|---|---|---|
| 使い捨て | Podはいつでも削除・再作成される | Pod内にデータを保存してはいけない |
| IPアドレスが変わる | 再作成のたびに新しいIPが振られる | IPで直接通信してはいけない (→ Serviceで解決、第3回) |
| 1 Pod = 1プロセスグループ | 同じPod内のコンテナは、 ネットワーク・ストレージを共有 |
localhost で通信可能 |
🍽️ Podは 「紙皿」
汚れたら捨てて新しいのを出す。
陶器の皿(永続サーバー)のように大事に使い続けるものではない。
5. ReplicaSetとは?
5-1. 一言で言うと
ReplicaSetは「Podを指定した数だけ維持するコントローラー」
| 観点 | Docker Compose | k8s |
|---|---|---|
| 台数指定 | docker-compose up --scale web=3 |
ReplicaSet の replicas: 3
|
| 台数の維持 | しない(落ちたら落ちたまま) | 自動で維持する |
| 管理対象 | コンテナ | Pod |
5-2. 🍽️飲食チェーンで例えると?
🍽️ Pod = 店員、ReplicaSet = シフト管理表
「この店舗は常に3人体制」とシフト表に書いておく。
- 1人休んだら → 代わりの人を自動で呼ぶ
- 多すぎたら → 1人帰らせる
- シフト表に書かれた人数を常にキープするのがReplicaSetの仕事
5-3. ReplicaSetの動き
5-4. 数を維持する仕組み:Reconciliation Loop
ReplicaSet は、「理想と現実を常に比較し続ける」ループで動いています。
🍽️ 巡回マネージャーの日常:
- シフト表を見る →「渋谷店は3人体制のはず」
- 渋谷店を確認 →「今何人いる?」
- 比較する → OK or 補充 or 帰らせる
- 次の店舗へ…そしてまた渋谷店に戻ってくる
これを永遠に繰り返す。
5-5. 具体的なシナリオ
5-5-1. Podがクラッシュした場合
| 時刻 | 理想 | 現実 | 判断 | アクション |
|---|---|---|---|---|
| 10:00 | 3 | 3 | 一致 | 何もしない |
| 10:01 | 3 | 2(Pod C死亡) | 不足 | Pod D を作成 |
| 10:02 | 3 | 3(Pod D起動完了) | 一致 | 何もしない |
5-5-2. replicas を3→5に変更した場合
| 時刻 | 理想 | 現実 | 判断 | アクション |
|---|---|---|---|---|
| 10:00 | 3 | 3 | 一致 | 何もしない |
| 10:01 | 5(YAML変更) | 3 | 不足 | Pod D, E を作成 |
| 10:02 | 5 | 5 | 一致 | 何もしない |
5-6. Docker Composeとの決定的な違い
| 観点 | 🚫Docker Compose | ✅k8s(ReplicaSet) |
|---|---|---|
| 台数指定 | docker-compose up --scale web=3 |
replicas: 3 |
| 落ちた時 | 落ちたまま。手動で再起動 | 自動で補充 |
| 監視 | なし(自分で確認) | 常時監視(Reconciliation Loop) |
🚫Docker Compose = 掲示板に「3人体制」と貼るだけ。誰も見てない。
✅k8s = 巡回マネージャーが24時間体制で見回って、3人を維持してくれる。
5-7. 重要:ReplicaSetは直接使わない
| 疑問 | 答え |
|---|---|
| ReplicaSetを直接作るの? | いいえ。Deploymentが自動で作ってくれる |
| じゃあなぜ学ぶ? | Deploymentの中身を理解するため |
6. Deploymentとは?
6-1. 一言で言うと
DeploymentはReplicaSetを管理し、
さらに「アプリのバージョン更新」を安全に行うコントローラー。
| 観点 | ReplicaSet | Deployment |
|---|---|---|
| Podの数を維持 | ✅ できる | ✅ できる(ReplicaSet経由) |
| アプリのバージョン更新 | ❌ できない | ✅ ローリングアップデート |
| ロールバック(巻き戻し) | ❌ できない | ✅ 前のバージョンに戻せる |
| 実務で使うか | 直接は使わない | ★これを使う★ |
6-2. 3層構造
| 層 | 役割 | 🍽️飲食チェーン比喩 |
|---|---|---|
| Deployment | アプリのバージョン管理 + ReplicaSet管理 | 店舗マネージャー |
| ReplicaSet | 指定数のPodを維持 | シフト管理表 |
| Pod | 実際にコンテナが動く | 店員 |
6-3. ローリングアップデート
6-3-1. 全体フロー図
アプリを v1→v2 に更新する時、
DeploymentはPodを1つずつ安全に入れ替えます。
サービス停止ゼロで更新完了。
🍽️飲食チェーン:
❌ 危険な方法 = 全店同時に閉店 → 改装 → 全店同時に再開
✅ ローリングアップデート = 1店舗ずつ順番に改装。残りの店舗が営業を続ける。
6-3-2. 分割版フロー図:3つのフェーズで理解する
上の流れを 「開始→入れ替え中→完了」 の3フェーズに分けて見てみます。
Phase 1/更新の開始 — 新ReplicaSetの作成と最初のv2起動(①〜③)
🍽️ オーナーが、
「新メニューに切り替えて」と指示 → 本部が新メニュー担当チームを1人配置するまで
Phase 2/段階的な入れ替え — v1縮小とv2拡大を交互に繰り返す(④〜⑨)
🍽️ 旧メニュー担当を1人ずつ帰し、新メニュー担当を1人ずつ配置。
常に店舗は営業中。
Phase 3/入れ替え完了 — 旧ReplicaSetの停止(⑪〜⑫)
🍽️ 旧メニュー担当が全員退勤。
新メニュー3人体制で営業再開完了。お客さんは一度も待たされていない。
6-4. ローリングアップデートの制御:maxSurge / maxUnavailable
入れ替えの「速さと安全性」を制御する2つのパラメータです。
| パラメータ | 意味 | デフォルト |
|---|---|---|
| maxSurge | 理想数を超えて同時に存在できるPod数 | 25% |
| maxUnavailable | 理想数を下回って良いPod数 | 25% |
🍽️ 3人体制の店舗でスタッフを入れ替える場面:
- maxSurge = 「一時的に何人まで多くてOK?」
- maxUnavailable = 「一時的に何人まで少なくてOK?」
6-4-1. パターン比較(replicas: 3)
| パターン | maxSurge | maxUnavailable | 特徴 |
|---|---|---|---|
| 安全重視 | 1 | 0 | 常に3つ以上を維持 新Podを先に起動 |
| 速度重視 | 1 | 1 | 起動と停止を同時実行 一瞬2つになる |
| リソース節約 | 0 | 1 | 追加Pod不要 先に停止してから起動 |
🔰 ネットワークエンジニア的な対比:
- maxSurge:1, maxUnavailable:0 → Make-before-break(新経路確立→旧経路切断)
- maxSurge:0, maxUnavailable:1 → Break-before-make(旧経路切断→新経路確立)
6-4-2. デフォルト25%の計算例
端数処理ルール:maxSurge は切り上げ、maxUnavailable は切り捨て。
| replicas | maxSurge(25%) | maxUnavailable(25%) | 最大Pod数 | 最小稼働数 |
|---|---|---|---|---|
| 1 | 1(0.25→切り上げ→1) | 0(0.25→切り捨て→0) | 2 | 1 |
| 3 | 1(0.75→切り上げ→1) | 0(0.75→切り捨て→0) | 4 | 3 |
| 4 | 1(1.0→そのまま) | 1(1.0→そのまま) | 5 | 3 |
| 10 | 3(2.5→切り上げ→3) | 2(2.5→切り捨て→2) | 13 | 8 |
| 100 | 25(25.0→そのまま) | 25(25.0→そのまま) | 125 | 75 |
🔰 注目:
replicas:3 だとmaxUnavailableが0になる。
つまり「1つも減らせない」ので、
必ず先に新Podを起動してから旧Podを停止する安全な動きになる。
⚠️ 注意:
maxSurge:0 かつ maxUnavailable:0 は、
デッドロック(増やせない、減らせない → 入れ替え不可能)になるため設定不可です。
6-5. ロールバック:前のバージョンに戻す
Deploymentは旧ReplicaSetを削除しないで残しているため、すぐに前のバージョンに戻せます。
🍽️ 新メニューが不評だった → 「旧メニューの印刷物は倉庫に保管してある」→ すぐ旧メニューに戻せる。
# 更新履歴一覧を確認
kubectl rollout history deployment/web-app
# 1つ前に戻す
kubectl rollout undo deployment/web-app
# 特定のrevisionに戻す
kubectl rollout undo deployment/web-app --to-revision=1
6-6. revision番号の振り直し
ロールバック時のrevision番号の動きは直感に反するため注意が必要だと思います。
| 操作 | やったこと | revision 1 | revision 2 | revision 3 | revision 4 |
|---|---|---|---|---|---|
| ① 初回デプロイ | nginx:1.19 | RS-A(稼働中) | - | - | - |
| ② v2に更新 | nginx:1.20 | RS-A(待機) | RS-B(稼働中) | - | - |
| ③ v3に更新 | nginx:1.21 | RS-A(待機) | RS-B(待機) | RS-C(稼働中) | - |
| ④ v2にロールバック | undo --to-revision=2 |
RS-A(待機) | 消滅 | RS-C(待機) | RS-B(稼働中) |
ポイント:
| ルール | 説明 |
|---|---|
| revision番号は常に増加 | 巻き戻しても番号は進む。「rev 2に戻す」≠「rev番号が2に戻る」 |
| 使ったrevisionは最新番号に昇格 | RS-Bがrevision 2 → revision 4に移動 |
| 旧revision番号は消滅 | revision 2の枠は空(欠番)になる |
🍽️「冬メニューから春メニューに戻す」場合
「改定2に戻す」ではなく「春メニューを改定4として再採用した」
🔰 gitで例えると:
git revertに近い(過去の状態に戻すが履歴は進む)。
ただし仕組みは異なり、既存のReplicaSetを再昇格させる(新しい「打ち消し」は作らない)。revision番号は進む。
6-6-1. 履歴保持数の制限
| 設定 | デフォルト値 | 意味 |
|---|---|---|
revisionHistoryLimit |
10 | 保持するReplicaSetの数 |
spec:
revisionHistoryLimit: 5 # 直近5世代まで保持
🍽️ 倉庫のスペースには限りがある。
「直近の10版分のメニューだけ保管、それ以前は廃棄」→ 古すぎバージョンには戻せなくなる。
6-7. Docker Composeとの最終比較
| やりたいこと | Docker Compose | k8s Deployment |
|---|---|---|
| コンテナ起動 | docker-compose up |
kubectl apply -f deployment.yaml |
| 台数変更 | --scale web=5 |
replicas: 5 に変更 → apply |
| バージョン更新 | イメージ変更 → up -d → 瞬断あり
|
イメージ変更 → apply → ゼロダウンタイム |
| 元に戻す | 手動でイメージを戻して再起動 |
kubectl rollout undo → 1コマンド
|
| 自動復旧 | なし | Podが落ちたら自動復旧 |
7. Deployment YAMLの書き方
7-1. Docker Compose と k8s YAML の対比
やりたいこと: nginxコンテナを3つ起動
7-1-1. Docker Compose
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx:1.21
ports:
- "80:80"
deploy:
replicas: 3
7-1-2. k8s Deployment
# deployment.yaml
apiVersion: apps/v1 # どのAPIバージョンを使うか
kind: Deployment # リソースの種類
metadata: # このリソースの名前やラベル
name: web-app
spec: # Deploymentの仕様
replicas: 3 # Pod数
selector: # 管理対象のPodを特定する条件
matchLabels:
app: web
strategy: # 更新戦略
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template: # Podのテンプレート(設計図)
metadata:
labels: # Podに貼るラベル
app: web
spec: # Podの中身
containers:
- name: nginx # コンテナ名
image: nginx:1.21 # コンテナイメージ
ports:
- containerPort: 80 # コンテナのポート
7-2. 対応マップ
| DockerCompose | k8s Deployment | 備考 |
|---|---|---|
services: web: |
kind: Deployment + metadata.name
|
リソースの定義 |
image: |
spec.template.spec.containers[].image |
同じ |
ports: |
containerPort: |
k8sでは外部公開は別(Service、第3回) |
replicas: |
spec.replicas |
同じ概念 |
| (なし) |
selector + labels
|
k8s特有。重要 |
| (なし) | strategy |
k8s特有。ローリングアップデート制御 |
7-3. YAMLの全体構造マップ
7-4. k8s特有の重要概念:labels と selector
7-4-1. labelsとは?
キー:値のペアで、k8sのあらゆるリソースに貼れるタグです。
metadata:
labels:
app: web # アプリ名
env: production # 環境
team: backend # チーム
version: v2 # バージョン
🍽️ labels = 店員に貼る複数のネームプレート
「所属:ホール」「店舗:渋谷」「スキル:バリスタ」「シフト:朝番」
複数のプレートを組み合わせて「渋谷店のホール担当で朝番の人」と検索できる
7-4-2. selectorとは?
labelsを使って「どのリソースを管理対象にするか」を指定する仕組みです。
selector:
matchLabels:
app: web # 「app=web」のPodを管理対象にする
7-4-3. なぜ DockerCompose では不要だった?
| 疑問 | 答え |
|---|---|
| DockerComposeでは? |
services: web: という名前で1対1対応が暗黙的に決まる |
| k8sでは? | 大量のPodが混在する。「誰が誰を管理するか」を明示する必要がある |
| selectorとlabelsが一致しないと? | Deploymentがどのpodも管理できず、エラーになる |
7-4-4. labels/selector が使われる場面は?
Deploymentだけの仕組みではなく、k8s全体を貫く仕組みです。
| 使う側 | 何のために selector を使う | 学ぶ回(記事) |
|---|---|---|
| Deployment | 管理対象のPodを特定 | 第2回(本記事) |
| ReplicaSet | 数を維持するPodを特定 | 第2回(本記事) |
| Service | 通信を振り分けるPodを特定 | 第3回 |
| NetworkPolicy | 通信を許可するPodを特定 | 第3回〜4回 |
🍽️ labelsは「店員のネームプレート」だが、読む人がたくさんいる:
- シフト管理表(Deployment/ReplicaSet)→ 「ホール担当を3人維持」
- 電話交換台(Service)→ 「ホール担当に電話を振り分ける」
- セキュリティ(NetworkPolicy)→ 「ホール担当は厨房には入れない」
7-4-5. 実務でよく使うlabelパターンは?
| ラベルキー | 用途 | 例 |
|---|---|---|
app |
アプリケーション名 |
app: web, app: api
|
env |
環境 |
env: production, env: staging
|
version |
バージョン |
version: v2, version: canary
|
team |
担当チーム |
team: backend, team: infra
|
tier |
アーキテクチャ層 |
tier: frontend, tier: backend
|
7-4-6. ⚠️ 実務テクニック:labelを手動で剥がしてデバッグ
問題のあるPodのlabelを外すと、Deploymentの管理から外れます。
代わりの健全なPodが自動で補充されつつ、問題のPodは調査用に残せます。
# Pod Aのlabelを剥がす
kubectl label pod web-app-xxx app-
# 結果:
# - Pod A は管理外になる(でもまだ動いてる)
# - Deploymentは「Podが足りない」と判断して新しいPod Dを作成
🍽️ 店員Aのネームプレート(「ホール担当」)を外した → シフト管理表は「ホール担当が足りない!」と新人Dを補充 → Aは「誰の管理下でもない野良スタッフ」として調査可能
8. ハンズオン:Deploymentを操作する
8-1. 作業ディレクトリ
# ホームディレクトリで実行
cd ~
mkdir -p k8s-practice/pod-deployment
cd k8s-practice/pod-deployment
8-2. この記事で作成するファイル
~/k8s-practice/
└── pod-deployment/ ← 今回はここ
└── deployment.yaml
8-3. Deployment YAMLの作成
# deployment.yaml
# Deployment: nginxコンテナを3つ起動
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
8-4. Deploymentの作成と確認
# Deploymentを作成
kubectl apply -f deployment.yaml
期待される出力:
deployment.apps/web-app created
# Deploymentの状態を確認
kubectl get deployment web-app
期待される出力:
NAME READY UP-TO-DATE AVAILABLE AGE
web-app 3/3 3 3 30s
🔰 出力の読み方:
| 列 | 意味 | 今回の値 |
|---|---|---|
| READY | 準備完了のPod数/理想数 | 3/3(全部OK) |
| UP-TO-DATE | 最新テンプレートで動いてるPod数 | 3 |
| AVAILABLE | 利用可能なPod数 | 3 |
# Pod一覧を確認
kubectl get pods -l app=web
期待される出力:
NAME READY STATUS RESTARTS AGE
web-app-xxxxxxxxx-xxxxx 1/1 Running 0 30s
web-app-xxxxxxxxx-yyyyy 1/1 Running 0 30s
web-app-xxxxxxxxx-zzzzz 1/1 Running 0 30s
# ReplicaSetも自動で作られていることを確認
kubectl get replicaset
期待される出力:
NAME DESIRED CURRENT READY AGE
web-app-xxxxxxxxx 3 3 3 30s
8-5. スケーリングを試す
# 3→5にスケールアップ
kubectl scale deployment web-app --replicas=5
# Pod数を確認
kubectl get pods -l app=web
期待される出力: Podが5つに増えている。
# 5→2にスケールダウン
kubectl scale deployment web-app --replicas=2
# Pod数を確認
kubectl get pods -l app=web
期待される出力: Podが2つに減っている。
# 元の3に戻す
kubectl scale deployment web-app --replicas=3
8-6. ローリングアップデートを試す
# イメージを nginx:1.21 → nginx:1.22 に更新
kubectl set image deployment/web-app nginx=nginx:1.22
# ロールアウトの状況をリアルタイム確認
kubectl rollout status deployment/web-app
期待される出力:
Waiting for deployment "web-app" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "web-app" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "web-app" successfully rolled out
# 更新履歴を確認
kubectl rollout history deployment/web-app
8-7. ロールバックを試す
# 1つ前のバージョンに戻す
kubectl rollout undo deployment/web-app
# 戻ったことを確認
kubectl describe deployment web-app | grep Image
期待される出力:
Image: nginx:1.21
8-8. お片付け
# Deploymentを削除(関連するReplicaSet、Podも全て削除される)
kubectl delete deployment web-app
# 確認
kubectl get all
9. まとめ
9-1. 本記事で学んだこと
| # | 学んだこと | キーポイント |
|---|---|---|
| ① | Podの基本 | k8sの最小単位。使い捨て。99%は1 Pod = 1コンテナ |
| ② | ReplicaSetの仕組み | Reconciliation Loopで指定数を常時維持 |
| ③ | Deploymentの3層構造 | Deployment → ReplicaSet → Pod の階層で管理 |
| ④ | ローリングアップデート | ゼロダウンタイムでバージョン更新。maxSurge/maxUnavailableで制御 |
| ⑤ | ロールバック | 旧ReplicaSetを保持。1コマンドで巻き戻し。revision番号は常に増加 |
| ⑥ | labels/selector | k8s全体を貫くタグ付けと検索の仕組み |
9-2. ゴールの達成確認
| # | ゴール | 達成状況 |
|---|---|---|
| ① | 3層構造を説明できる | ✅ セクション6-2で解説 |
| ② | ローリングアップデートを説明できる | ✅ セクション6-3, 6-4で解説 |
| ③ | ロールバックの履歴管理を理解している | ✅ セクション6-5, 6-6で解説 |
| ④ | Deployment YAMLを読み書きできる | ✅ セクション7で解説 |
| ⑤ | labels/selectorを説明できる | ✅ セクション7-4で解説 |
9-3. 次回予告
第3回:Service と Ingress でネットワークを理解する
次回は、Podへの通信経路を作るServiceと、外部からのアクセスを制御するIngressを学びます。Docker Composeの ports に対応する概念ですが、k8sではより柔軟で強力な仕組みになっています。