Dockerでコンテナを動かせるようになった。Docker Composeで複数コンテナも管理できる。
「じゃあ、これで本番環境もいけるのでは?」
…残念ながら、そう簡単にはいきません。
サーバーが増え、コンテナが増え、ユーザーが増えると、Dockerだけでは対処できない壁にぶつかります。
この記事では、Dockerの限界を明確にした上で、それを解決するために生まれたKubernetes(クバネティス) の設計思想とアーキテクチャを、図解を交えながら体系的に解説します。
この記事を読み終わる頃には、
- Dockerだけでは本番運用が難しい理由を説明できる
- Kubernetesの設計思想(なぜそう作られたか)を理解している
- クラスターのアーキテクチャ(Control Plane / Data Plane)を図解できる
- kubectlの基本的な役割と使い方を把握している
状態を目指します。
TL;DR
| ポイント | 内容 |
|---|---|
| Dockerの限界 | 単一ホスト向け。複数サーバーでの自動配置・復旧・スケールができない |
| Kubernetesとは | Googleの15年の知見から生まれたコンテナオーケストレーター |
| 設計思想 | 自動化・宣言的・スケーラブル・レジリエント の4本柱 |
| アーキテクチャ | Control Plane(脳)が判断し、Data Plane(体)が実行する |
| 解決する問題 | 自動配置、負荷分散、自動スケール、自己修復、名前解決、構成管理 |
| kubectl | クラスターへの「リモコン」。YAMLで「あるべき姿」を定義する |
対象読者
- Dockerの基本(
docker run、Dockerfile)を理解している方 - Docker Composeで複数コンテナを管理した経験がある方
- 「Kubernetesってよく聞くけど、何がすごいの?」と思っている方
この記事は概念理解に焦点を当てています。
具体的なハンズオン(minikubeでの構築やPodのデプロイ)は扱いません。
「まず全体像を掴んでから手を動かしたい」という方に最適です。
Step 1: Dockerの成功と「本番運用」の壁
Dockerが解決したこと(振り返り)
まずは、Dockerがいかに素晴らしいツールかを振り返りましょう。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【Dockerが解決した世界】 │
│ │
│ Before: │
│ 「自分のPCでは動くのに、サーバーでは動かない...」 │
│ │
│ After: │
│ Dockerfileに書く → どこでも同じ環境が再現される │
│ │
│ ✓ 環境差異の解消 │
│ ✓ 軽量な仮想化 │
│ ✓ Docker Composeで複数コンテナの一括管理 │
│ │
└─────────────────────────────────────────────────────────────────┘
開発環境としてのDockerは、間違いなく革命的です。
Dockerfileを書けば環境を再現でき、Docker Composeを使えばBackend + DB + Cacheのような構成も docker compose up 一発で起動できます。
では、この便利なDockerを「本番環境」に持っていったらどうなるでしょうか?
本番環境で直面する5つの壁
開発環境と本番環境の決定的な違いは、サーバーが複数台あることです。
ここで、Dockerだけでは解決できない壁が立ちはだかります。
壁①: 複数サーバーへの手動配置が破綻する
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【開発環境(1台)】 【本番環境(複数台)】 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 自分のPC │ │ Server1 │ │ Server2 │ │
│ │ │ │ │ │ │ │
│ │ docker │ │ docker │ │ docker │ │
│ │ compose │ │ run ??? │ │ run ??? │ │
│ │ up ✓ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ → 1台なら簡単 │ Server3 │ │ Server4 │ │
│ │ run ??? │ │ run ??? │ │
│ └──────────┘ └──────────┘ │
│ │
│ → どのサーバーに何を配置する? │
│ → CPUやメモリの空きは? │
│ → 10台、100台になったら? │
│ │
└─────────────────────────────────────────────────────────────────┘
サーバーが増えるほど、「どのサーバーにどのコンテナを置くか」を人間が判断するのは不可能に近づきます。
壁②: コンテナが死んでも誰も気づかない
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 深夜2時、アプリがクラッシュ │
│ │
│ ┌──────────┐ │
│ │ App │ → 💥 クラッシュ! │
│ └──────────┘ │
│ │
│ → 誰が気づく? │
│ → 誰が再起動する? │
│ → docker restart? でもSSHで繋がないと... │
│ → その間、ユーザーはエラー画面を見ている │
│ │
└─────────────────────────────────────────────────────────────────┘
Dockerの restart: always は同一ホスト内での再起動しかできません。サーバーごと落ちた場合は対応できません。
壁③: アクセス急増に手動スケールが追いつかない
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 通常時: アクセス 100件/秒 → コンテナ2つで十分 │
│ │
│ 突然: アクセス 10,000件/秒 → コンテナ2つではパンク! │
│ │
│ 【手動対応の場合】 │
│ ① エンジニアに連絡 (5分) │
│ ② サーバーを確認 (5分) │
│ ③ 新しいサーバーを用意 (10分) │
│ ④ Dockerインストール、docker run... (10分) │
│ │
│ → 対応完了まで30分。その間サービスがパンク。 │
│ │
└─────────────────────────────────────────────────────────────────┘
壁④: サーバー間で設定がバラバラになる
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Server1: nginx:1.24 環境変数: DB_HOST=db-old │
│ Server2: nginx:1.25 環境変数: DB_HOST=db-new ← あれ? │
│ Server3: nginx:1.24 環境変数: DB_HOST=db-old │
│ │
│ → バージョンが揃っていない │
│ → 環境変数も微妙に違う │
│ → 「Server2だけ動かない」問題が頻発 │
│ │
└─────────────────────────────────────────────────────────────────┘
壁⑤: デプロイのたびにサービスが止まる
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【従来のデプロイ】 │
│ │
│ 旧バージョン停止 ──── サービス停止中 ──── 新バージョン起動 │
│ ↑ │
│ この間、ユーザーはアクセスできない │
│ │
│ → ダウンタイムが発生する │
│ → 深夜にデプロイするしかない │
│ │
└─────────────────────────────────────────────────────────────────┘
Dockerの守備範囲を整理する
ここまでの内容を整理しましょう。Dockerが悪いわけではありません。守備範囲が違うのです。
| 環境 | Docker / Docker Compose | 評価 |
|---|---|---|
| ローカル開発 | 完璧。環境再現、複数コンテナ管理 | ✅ |
| 小規模な本番(単一サーバー) | シンプルでなんとかなる | ✅ |
| 中〜大規模の本番(複数サーバー) | 自動配置・復旧・スケールができない | ❌ |
この「複数サーバーでの自動化」という課題を解決するために、Kubernetesが生まれました。
Step 2: Kubernetesの誕生 - Googleの15年の知見
Googleが直面していた課題
実は、「大量のコンテナをどう管理するか」という課題に、GoogleはDockerが登場するずっと前から取り組んでいました。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【Googleの規模感】 │
│ │
│ ・世界中のデータセンターで数十億のコンテナを運用 │
│ ・Gmail、YouTube、Google検索...すべてコンテナで動いている │
│ ・2003年頃から社内ツール「Borg」で管理 │
│ │
│ 2003年 2013年 2014年 現在 │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Borg │ │Docker│ │ K8s │ │ 業界 │ │
│ │(社内) │ ... │ 登場 │ → │ 公開 │ → │ 標準 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ Googleの知見 → コンテナ普及 → K8s誕生 → 業界標準化 │
│ │
└─────────────────────────────────────────────────────────────────┘
Googleは社内で10年以上「Borg」というオーケストレーションシステムを運用し、大規模コンテナ管理のノウハウを蓄積していました。
Dockerの登場とオーケストレーションの必要性
2013年にDockerが登場し、コンテナ技術が一般のエンジニアにも普及しました。
すると、世界中の企業がGoogleと同じ課題に直面し始めます。
「コンテナは作れる。でも、大量のコンテナをどう管理すればいいのか?」
この課題を解決するのがコンテナオーケストレーションです。
オーケストラの指揮者が多数の楽器奏者を束ねるように、多数のコンテナを自動で管理する仕組みです。
Kubernetes誕生(2014年)と業界標準化
2014年、GoogleはBorgで培った知見をオープンソースとして公開しました。
それがKubernetes(ギリシャ語で「操舵手」の意味、通称K8s)です。
現在では、AWS(EKS)、Azure(AKS)、GCP(GKE)の主要クラウドすべてがKubernetesをサポートしており、コンテナオーケストレーションのデファクトスタンダード(業界標準) となっています。
「ツール」ではなく「プラットフォーム」
Kubernetesの特筆すべき点は、単なるツールではなくプラットフォームとして設計されていることです。
デフォルトの機能だけでなく、何千ものサードパーティ製ツール(エコシステム)を追加して、監視・セキュリティ・デプロイ管理などを強化できます。この拡張性の高さが、Kubernetesが業界標準になれた大きな理由のひとつです。
Step 3: Kubernetesを支える4つの設計思想
Kubernetesの各機能を学ぶ前に、その設計思想を理解しておきましょう。
設計思想を知っていると、「なぜこの機能があるのか」「なぜこう動くのか」が腹落ちしやすくなります。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Kubernetesの4本柱 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ ① 自動化 │ │ ② 宣言的 │ │
│ │ Automation │ │ Declarative │ │
│ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ ③ 拡張性 │ │ ④ 回復力 │ │
│ │ Scalability │ │ Resilience │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ この4つの思想が、全ての機能の根底にある │
│ │
└─────────────────────────────────────────────────────────────────┘
① 自動化(Automation)
Step 1で見た「手動でSSHしてdocker run...」の世界から脱却し、人間の介入を最小限に抑えます。
人間がやること:「あるべき姿」を定義する(YAMLファイルを書く)
Kubernetesがやること:その姿を実現し、維持し続ける
手動作業が減れば、ヒューマンエラーも減ります。
② 宣言的スタイル(Declarative)
Kubernetesの最も核心的な概念です。ここをしっかり理解しておくと、後の学習がぐっと楽になります。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【命令的(Imperative)】 │
│ │
│ 「手順」を一つずつ指示する │
│ │
│ docker run -d --name app1 nginx │
│ docker run -d --name app2 nginx │
│ docker run -d --name app3 nginx │
│ │
│ → 「何を」「どの順番で」やるか、全て人間が指示 │
│ → 1つ壊れても、気づいて再実行するのは人間 │
│ │
│ vs │
│ │
│ 【宣言的(Declarative)】 │
│ │
│ 「最終的な状態」だけ定義する │
│ │
│ replicas: 3 ← 「nginxが3つ動いている状態にして」 │
│ │
│ → 手段はKubernetesが考える │
│ → 1つ壊れたら、自動で3つに戻してくれる │
│ │
└─────────────────────────────────────────────────────────────────┘
なぜこれが重要なのでしょうか?
ユーザーが「あるべき姿(Desired State)」をファイルに記述して渡せば、Kubernetesは常に現状を監視し、差分があれば自動で修復してくれるからです。この「監視→差分検知→修復」のサイクルをリコンシリエーション・ループと呼びます。
この仕組みがあるからこそ、エンジニアは「コンテナをどう動かすか」という低レベルな作業から解放され、「システムをどうあるべきか」という定義に集中できるのです。
③ スケーラビリティ(Scalability)
需要の増減に合わせて、アプリケーションを水平スケーリングさせることが容易です。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【水平スケーリング(Horizontal Scaling)】 │
│ │
│ 負荷が低い時: [Pod] [Pod] ← 2つで十分 │
│ │
│ 負荷が高い時: [Pod] [Pod] [Pod] [Pod] [Pod] ← 自動で増加 │
│ │
│ 負荷が戻った: [Pod] [Pod] ← 自動で縮小 │
│ │
│ → コンテナの数(インスタンス数)を増減して対応 │
│ → アプリケーション側の変更は不要 │
│ │
└─────────────────────────────────────────────────────────────────┘
④ レジリエンス(Resilience / 回復力)
障害が発生してもサービスを継続させる仕組みです。
Kubernetesは2つの方法でレジリエンスを実現します。
自動再スケジュール: ノード(サーバー)が故障した場合、その上で動いていたコンテナを自動で別の健全なノードへ移動させます。
ローリングアップデート: 新しいバージョンへの更新時、新しいコンテナが正常に動き始めたことを確認してから古いコンテナを停止します。Step 1の「壁⑤: デプロイ時のダウンタイム」を解決する仕組みです。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【ローリングアップデート】 │
│ │
│ ① [v1] [v1] [v1] ← 旧バージョンが3つ稼働中 │
│ ② [v1] [v1] [v1] [v2] ← 新バージョンを1つ追加 │
│ ③ [v1] [v1] [v2] [v2] ← 新v2が正常なら、v1を1つ停止 │
│ ④ [v1] [v2] [v2] [v2] ← さらに入れ替え │
│ ⑤ [v2] [v2] [v2] ← 完了。ダウンタイムなし │
│ │
│ → サービスを止めずにデプロイできる │
│ │
└─────────────────────────────────────────────────────────────────┘
Step 4: Kubernetesが解決する6つの問題
設計思想を理解したところで、Kubernetesが具体的に何を自動化してくれるのかを見ていきましょう。
Step 1で挙げた課題が、ここで解決されます。
① コンテナ・スケジューリング(自動配置)
どのコンテナをどのサーバー(ノード)で実行するかを自動で決定します。
なぜ必要なのでしょうか?
Step 1の「壁①」で見たように、複数サーバーへの手動配置は破綻するからです。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【Before: 手動配置】 │
│ │
│ エンジニア: 「Server1のCPUは...80%か。 │
│ Server2は...30%だからこっちに置こう」 │
│ │
│ → 100台のサーバーでこれをやるのは不可能 │
│ │
│ 【After: Kubernetes Scheduler】 │
│ │
│ YAMLに書くだけ: replicas: 3 │
│ │
│ Scheduler が自動で判断: │
│ ├── Node1 (CPU 90%) → ✗ リソース不足 │
│ ├── Node2 (CPU 30%) → ✓ 採用! │
│ └── Node3 (CPU 50%) → ✓ 採用! │
│ │
└─────────────────────────────────────────────────────────────────┘
ユーザーは「何を動かしたいか」を宣言的に定義するだけで、Kubernetesが空いているリソースを探し、自動で適切なノードに配置します。
② ロードバランシング(負荷分散)- Serviceの仕組み
外部からのアクセスを複数のコンテナに均等に振り分けます。
なぜ必要なのでしょうか?
特定のコンテナにアクセスが集中すると、そのコンテナだけがパンクしてしまうからです。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 外部からのアクセス │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ Service │ ← 単一のアクセスポイント │
│ └────┬─────┘ │
│ │ 自動で負荷分散 │
│ ┌────┼────┬────┐ │
│ ▼ ▼ ▼ ▼ │
│ Pod1 Pod2 Pod3 Pod4 │
│ │
│ → ユーザーはServiceにアクセスするだけ │
│ → 背後のPodへの振り分けはKubernetesが自動で行う │
│ │
└─────────────────────────────────────────────────────────────────┘
ServiceというKubernetesの仕組みが、背後にある複数のPodに通信を自動で振り分けます。
③ オートスケーリング(自動増減)- HPAの仕組み
負荷に応じてコンテナの数を自動で増減させます。
なぜ必要なのでしょうか?
Step 1の「壁③」で見たように、手動スケールでは急増するアクセスに追いつけないからです。
Horizontal Pod Autoscaler(HPA) がCPU使用率やメモリ消費などのメトリクスをリアルタイムで監視し、必要に応じてPodの数を自動調整します。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【手動スケール】 【HPA(自動スケール)】 │
│ │
│ アクセス急増! アクセス急増! │
│ │ │ │
│ ▼ ▼ │
│ エンジニアに連絡 CPU使用率上昇を検知 │
│ │ │ │
│ ▼ ▼ │
│ サーバー追加作業 自動でPod数を増加 │
│ │ │ │
│ ▼ ▼ │
│ 30分後に対応完了 数秒〜数分で対応完了 │
│ │
└─────────────────────────────────────────────────────────────────┘
④ セルフヒーリング(自己修復)- Liveness/Readiness Probe
異常が起きたコンテナを自動で検知・復旧させます。
なぜ必要なのでしょうか?
Step 1の「壁②」で見たように、24時間365日、人間が監視するのは現実的ではないからです。
Kubernetesはヘルスチェック機能(Liveness Probe / Readiness Probe) を使い、コンテナの健康状態を常に監視します。コンテナが応答しなくなれば自動で再起動し、ノードが故障すれば別の健全なノードへPodを移動(再スケジュール)させます。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【セルフヒーリングの流れ】 │
│ │
│ 正常時: [Pod1 ✓] [Pod2 ✓] [Pod3 ✓] Desired: 3, Actual: 3 │
│ │
│ 障害発生: [Pod1 ✓] [Pod2 💥] [Pod3 ✓] Desired: 3, Actual: 2 │
│ │
│ 自動検知: Controller が差分を検知 │
│ 「3つあるべきなのに2つしかない!」 │
│ │
│ 自動復旧: [Pod1 ✓] [Pod4 ✓] [Pod3 ✓] Desired: 3, Actual: 3 │
│ 新しいPod4が自動で作成される │
│ │
│ → 人間の介入なし。数秒〜数十秒で復旧 │
│ │
└─────────────────────────────────────────────────────────────────┘
⑤ サービスディスカバリ(名前解決)- 内蔵DNS
コンテナ同士が、相手のIPアドレスを知らなくても名前で通信できる仕組みです。
なぜ必要なのでしょうか?
Podは頻繁に作成・削除され、そのたびにIPアドレスが変わります。IPアドレスをハードコーディングすると、Podが再作成されるたびに接続が切れてしまいます。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【課題】 │
│ Pod再作成のたびにIPが変わる │
│ 接続先: 172.20.0.5 → Podが死んで再作成 → 172.20.0.12 │
│ → 古いIPへの接続は失敗する │
│ │
│ 【解決: Kubernetes内蔵DNS】 │
│ 接続先: "db-service" ← サービス名で指定 │
│ → IPが変わっても、DNSが自動で正しいPodに解決 │
│ │
│ 例: │
│ mongodb://db-service:27017 │
│ → 実際のIPはKubernetesが自動で解決 │
│ │
└─────────────────────────────────────────────────────────────────┘
⑥ 構成管理(ConfigMap / Secret)
アプリの設定値やパスワードなどの機密情報を安全に管理する仕組みです。
なぜ必要なのでしょうか?
Step 1の「壁④」で見たように、サーバーごとに設定がバラバラになる問題を防ぐためです。また、パスワードなどの機密情報を環境変数に直接書くのはセキュリティ上好ましくありません。
| オブジェクト | 用途 | 例 |
|---|---|---|
| ConfigMap | 一般的な設定値 | DB接続先、ポート番号、ログレベル |
| Secret | 機密情報(暗号化対応) | パスワード、APIキー、証明書 |
アプリケーションコードと設定を完全に分離し、環境(開発・ステージング・本番)ごとに切り替えることができます。
Docker vs Kubernetes 機能比較表
ここまでの内容を一覧で整理します。
| 機能 | Docker(単体) | Kubernetes |
|---|---|---|
| スケジューリング | 手動 | Schedulerが自動で配置 |
| ロードバランシング | 基本機能なし | Serviceによる標準装備 |
| スケーリング | 手動・低レベル設定 | HPAによる自動スケーリング |
| 自己修復 | 終了ステータスによる再起動のみ | 高度なヘルスチェックと再配置 |
| サービス発見 | コンテナ名でのリンク(限定的) | 内蔵DNSによる高度な名前解決 |
| 設定管理 | 環境変数など(低レベル) | ConfigMap / Secretによる抽象化 |
Step 5: アーキテクチャの全体像 - 脳と体
Kubernetesが「何を」解決するかは分かりました。
次は「どうやって」実現しているのか、アーキテクチャの全体像を見ていきましょう。
クラスターとノードとは
Kubernetesを使う際は、複数のコンピュータリソースを束ねたクラスターという単位で扱います。クラスターを構成する個々のサーバー(物理マシンまたは仮想マシン)をノードと呼びます。
Control Plane(脳)vs Data Plane(体)
クラスターは大きく2つの層に分かれています。人間の体に例えると分かりやすいです。
| コンポーネント | 別名 | 役割 |
|---|---|---|
| Control Plane | マスターノード / クラスターの脳 | クラスター全体の状態を管理し、「あるべき姿」を維持するための判断を下す |
| Data Plane | ワーカーノード / クラスターの体 | 実際にアプリケーション(コンテナ)が稼働する場所 |
全体構造図
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Control Plane (Master Node) │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌────────────┐ ┌──────────┐ │ │
│ │ │ API │ │ Scheduler │ │ Controller │ │ etcd │ │ │
│ │ │ Server │ │ │ │ Manager │ │ (DB) │ │ │
│ │ └─────┬─────┘ └───────────┘ └────────────┘ └──────────┘ │ │
│ └────────┼──────────────────────────────────────────────────┘ │
│ │ │
│ │ 指示・状態報告 │
│ │ │
│ ┌────────┼──────────────────────────────────────────────────┐ │
│ │ ▼ Worker Nodes (Data Plane) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Node 1 │ │ Node 2 │ │ Node 3 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ kubelet │ │ kubelet │ │ kubelet │ │ │
│ │ │ runtime │ │ runtime │ │ runtime │ │ │
│ │ │ kube-proxy │ │ kube-proxy │ │ kube-proxy │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ [Pod][Pod] │ │ [Pod] │ │ [Pod][Pod] │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ユーザー → kubectl → API Server → 各コンポーネント │
│ │
└─────────────────────────────────────────────────────────────────┘
高可用性(HA)の考え方
マスターノードが1台だけだと、そのノードが故障した際にクラスター全体が管理不能になります。
実運用では、耐障害性を高めるために複数のマスターノードを配置するのが一般的です。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【非推奨: マスター1台】 【推奨: マスター複数台】 │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Master │ ← 故障したら │ Master │ │ Master │ │
│ └────────┘ 管理不能に │ 1 │ │ 2 │ │
│ └────────┘ └────────┘ │
│ ┌────────┐ │
│ │ Master │ ← 1台壊れても │
│ │ 3 │ 他が引き継ぐ │
│ └────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
補足: ノードとVMの関係、minikube
Kubernetesはソフトウェアであり、物理的なハードウェアではありません。
本番環境では、通常1つのノードを1つの仮想マシン(VM)に対応させます。これにより、1台のVMが壊れてもクラスター全体が止まらないようにします。
一方、学習やローカル開発ではminikubeなどのツールを使い、自分のPC(1台の物理マシン)の中にクラスター環境をシミュレートして構築することも可能です。
Step 6: Control Plane - 司令塔の内部構造
Control Planeは、クラスター全体の状態を管理し、「あるべき姿」を維持するための司令塔です。
ここでは、その内部にある5つのコンポーネントの役割を見ていきます。
API Server(唯一の窓口、認証・認可)
それは何か?
クラスター操作の唯一の窓口となるコンポーネントです。
なぜ必要なのか?
クラスター内部の複雑な仕組みを隠蔽し、統一されたインターフェースを提供するためです。ユーザーやクラスター内の他のコンポーネントは、すべてAPI Serverを通じて通信を行います。セキュリティのための認証・認可もここで行われます。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【全ての通信はAPI Serverを経由する】 │
│ │
│ kubectl │
│ │ │
│ ▼ │
│ Scheduler ←→ API Server ←→ etcd │
│ ↕ │
│ Controller ←→ API Server │
│ ↕ │
│ kubelet │
│ │
│ → API Server が全ての通信のハブ │
│ │
└─────────────────────────────────────────────────────────────────┘
普段エンジニアが kubectl get pods と打つと、裏側ではAPI ServerへのHTTPリクエストが送信されています。
# ユーザーが実行するコマンド
kubectl get pods
# 裏側で起きていること(イメージ)
GET /api/v1/pods HTTP/1.1
Host: kubernetes-api-server
Authorization: Bearer <token>
Scheduler(配置の決定者)
それは何か?
新しく作成されたPodを、どのワーカーノードで動かすかを決定する担当者です。
なぜ必要なのか?
各サーバーの空き状況を手動で確認して配置するのは不可能だからです。Schedulerは「リソースの空き」や「設定されたルール」を瞬時に判断して最適なノードを選びます。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【Schedulerの判断例】 │
│ │
│ 新しいPod: 「メモリ2GB必要です」 │
│ │ │
│ ▼ │
│ Scheduler のチェック: │
│ │ │
│ ├── Node1 (空きメモリ: 1.5GB) → ✗ 不足 │
│ │ │
│ ├── Node2 (空きメモリ: 4.0GB) → ✓ 採用! │
│ │ │
│ └── Node3 (空きメモリ: 3.0GB) → △ 候補 │
│ │
│ → Node2 に配置決定 │
│ │
└─────────────────────────────────────────────────────────────────┘
Controller Manager(状態の監視者)
それは何か?
クラスターの状態を監視し、「あるべき姿」に保ち続けるためのプログラム(コントローラー)を集めたものです。
なぜ必要なのか?
システムには故障がつきものです。Podが死んだり、ノードがダウンしたりした際に、自動で復旧(セルフヒーリング)させるために必要です。
Controller Managerの中には、複数のコントローラーが含まれています。
| コントローラー名 | 役割 |
|---|---|
| ノードコントローラー | ノードが正常に動いているか監視する |
| レプリカセットコントローラー | 指定した数のPodが常に動いているか監視する |
| ジョブコントローラー | 指定したタスク(Job)が完了するまで実行を管理する |
どのコントローラーも共通して、「現在の状態」をチェックし、「あるべき姿(Desired State)」と差分があれば、それを埋めるアクションを起こすという動き方をします。
etcd(クラスターの記憶、Single Source of Truth)
それは何か?
クラスターに関するあらゆるデータ(設定情報や現在の状態)を保存する、高可用な分散型キーバリューストアです。
なぜ必要なのか?
Control Planeが再起動しても設定を忘れないようにするため、そしてクラスターの 「唯一の正解(Single Source of Truth)」 を保持するためです。
重要なルールとして、他のコンポーネントが直接etcdを触ることはありません。必ずAPI Serverを経由してデータを読み書きします。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【etcdへのアクセスルール】 │
│ │
│ Scheduler → API Server → etcd ✓ OK │
│ Controller → API Server → etcd ✓ OK │
│ kubelet → API Server → etcd ✓ OK │
│ │
│ Scheduler → etcd ✗ 直接アクセス禁止 │
│ │
│ → 全てAPI Serverを経由する │
│ │
└─────────────────────────────────────────────────────────────────┘
Cloud Controller Manager(クラウドとの橋渡し)
それは何か?
KubernetesとAWS、Azure、GCPといったクラウドプロバイダーの機能を橋渡しするコンポーネントです。
なぜ必要なのか?
Kubernetes自体は汎用的なソフトウェアであり、特定のクラウド操作の方法を知りません。例えば、AWSのロードバランサー(ELB)を作成したり、GCPのストレージを確保したりといったクラウド固有の操作には、専用の通訳が必要です。Cloud Controller Managerがその橋渡しを担います。
なお、オンプレミス環境やminikubeなどクラウドを使わない場合は不要です。
コンポーネント間の連携フロー
新しいPodを起動する際、Control Planeの各コンポーネントがどのように連携するかを見てみましょう。
Step 7: Data Plane - 実働部隊の内部構造
Control Planeが「脳」なら、Data Planeは「体」です。
ここには実際にアプリケーションが動くワーカーノードがあり、3つの必須コンポーネントが連携して動いています。
kubelet(ノードのエージェント、PodSpecの実行)
それは何か?
各ワーカーノードで実行されるエージェント(常駐プログラム) です。
なぜ必要なのか?
Control Planeからの指示を受け取り、それを実際のコンテナ操作に落とし込む必要があるからです。
kubeletは「現場監督」のような存在です。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【kubeletの仕事】 │
│ │
│ ① API Server から PodSpec(設計図)を受け取る │
│ ② Container Runtime に「コンテナ起動して」と指示 │
│ ③ Podの健康状態を監視 │
│ ④ 定期的にAPI Serverへ状態を報告 │
│ ⑤ コンテナが死んでいたら再起動させる │
│ │
│ → ノードの「現場監督」 │
│ │
└─────────────────────────────────────────────────────────────────┘
Container Runtime(Docker / containerd / CRI-O)
それは何か?
実際にコンテナを実行するためのソフトウェアです。
なぜ必要なのか?
Kubernetes自体はコンテナを起動する機能を持っていません。プロセスを分離してコンテナを作るための専門ツールが別途必要です。
代表的なContainer Runtimeは以下の通りです。
| ランタイム | 特徴 |
|---|---|
| Docker | かつて最も一般的だったもの。現在Kubernetesでは非推奨 |
| containerd | 現在の主流。Docker社が開発 |
| CRI-O | 軽量なランタイム |
KubernetesはCRI(Container Runtime Interface)という標準規格でContainer Runtimeを抽象化しています。そのため、どのランタイムでも同じように動作します。
kube-proxy(ネットワークの交通整理)
それは何か?
各ノードで動作するネットワークプロキシです。
なぜ必要なのか?
Podは頻繁に作成・削除され、そのたびにIPアドレスが変わります。外部や他のPodからの通信を、常に正しいPodへ転送(ルーティング)するために必要です。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【kube-proxyの役割】 │
│ │
│ Serviceへのアクセスを、実際のPodへ転送する │
│ │
│ 外部アクセス │
│ │ │
│ ▼ │
│ Service: 10.0.0.100:80 │
│ │ │
│ ▼ │
│ kube-proxy が振り分け │
│ │ │
│ ┌────┼────┬────┐ │
│ ▼ ▼ ▼ ▼ │
│ Pod1 Pod2 Pod3 Pod4 │
│ │
│ → Serviceと実際のPodの橋渡し │
│ → 簡易的な負荷分散も行う │
│ │
└─────────────────────────────────────────────────────────────────┘
Kubernetesオブジェクト(Pod / Deployment / Service / ReplicaSet / Job)
ワーカーノード上で「何がどのように動くか」を定義するのが、Kubernetesオブジェクトです。
| オブジェクト名 | 概要 |
|---|---|
| Pod | Kubernetesにおける最小単位。1つ以上のコンテナを含む |
| Deployment | Podの展開(アップデートやスケーリング)を管理する |
| Service | 複数のPodに一貫したアクセスポイント(IP/名前)を提供する |
| ReplicaSet | Podを常に指定した数だけ維持する |
| Job | 1回限りのタスクを実行し、完了を保証する |
これらはすべて「オプション」です。極端に言えば、Pod単体だけでも動かせます。しかし、本番環境で「自動復旧」や「負荷分散」を実現するためには、DeploymentやServiceといった上位オブジェクトの利用が不可欠です。
Control PlaneとData Planeの連携フロー
ここまで学んだコンポーネントが、実際にどう連携するかを整理します。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【Deploymentが適用された時の流れ】 │
│ │
│ ① Controller(Control Plane側) │
│ Deploymentの状態を監視 → 「Podが3つ必要だ」と判断 │
│ │ │
│ ▼ │
│ ② kubelet(Data Plane側) │
│ API Serverから「このノードでPodを動かせ」という指示を受取 │
│ │ │
│ ▼ │
│ ③ Container Runtime(Data Plane側) │
│ kubeletの指示で、実際にコンテナを起動 │
│ │ │
│ ▼ │
│ ④ kube-proxy(Data Plane側) │
│ そのPodへ通信ができるよう、ネットワークの通り道を作る │
│ │
└─────────────────────────────────────────────────────────────────┘
Step 8: kubectl - クラスターへのリモコン
ここまでKubernetesの内部構造を学んできました。
では、エンジニアは実際にどうやってクラスターを操作するのでしょうか?
その答えが kubectl(キューブコントロール / キューブカトル) です。
kubectlとは何か(APIリクエストへの翻訳者)
kubectlは、Kubernetesクラスターを管理・制御するための コマンドラインインターフェース(CLI) です。
Kubernetesの「脳」であるAPI ServerはHTTPリクエストを受け付けますが、人間が直接APIを叩くのは非常に煩雑です。kubectlは、人間が理解しやすいコマンドをAPI Serverが理解できるAPIリクエスト(HTTP)に翻訳して送信してくれる「通訳者」です。
なお、kubectlの他にもKubernetes DashboardというWeb UIを使ってクラスターを操作することもできます。ただし、エンジニアの日常業務ではkubectlを使うのが一般的です。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【kubectlの役割】 │
│ │
│ Kubernetes Cluster : アプリが動いている「環境本体」 │
│ kubectl : その環境へ指示を出す「リモコン」 │
│ │
│ kubectl自体がコンテナを動かすわけではなく、 │
│ あくまでAPI Serverへの「インターフェース」として機能する │
│ │
└─────────────────────────────────────────────────────────────────┘
コマンドの基本構造(command / TYPE / NAME / flags)
kubectlのコマンドは、一貫したシンプルな構造になっています。
kubectl [command] [TYPE] [NAME] [flags]
| 要素 | 意味 | 例 |
|---|---|---|
| command | 行いたい操作 |
get, describe, delete, apply
|
| TYPE | リソースの種類 |
pod, service, deployment
|
| NAME | 特定のリソース名(省略で全対象) |
my-app, nginx-pod
|
| flags | 追加のオプション |
-o wide, -n default
|
3つのユースケース
kubectlのコマンドは、目的に応じて大きく3つに分けられます。
① リソースの確認(調査・デバッグ)
クラスターの「現在の状態」を把握するために使います。
| コマンド | 用途 | 例 |
|---|---|---|
| get | リソースの一覧を表示 | kubectl get pods |
| describe | 特定リソースの詳細情報(イベント等)を表示 | kubectl describe pod my-app |
| logs | コンテナが出力しているログを表示 | kubectl logs my-app-pod |
② 命令的(Imperative)な管理
「〜を作れ」「〜を消せ」と、その場で直接指示を出す方法です。手軽ですが、変更履歴が残りにくい特徴があります。
| コマンド | 用途 | 例 |
|---|---|---|
| run | 新しいPodを起動 | kubectl run my-nginx --image=nginx |
| create | リソースを作成 | kubectl create deployment my-app --image=my-app:v1 |
| scale | レプリカ数を変更 | kubectl scale deployment my-app --replicas=5 |
| delete | リソースを削除 | kubectl delete pod my-nginx |
③ 宣言的(Declarative)な管理
「あるべき姿」を記述した設定ファイル(YAML)を読み込ませ、現在の状態をそれに合わせる方法です。本番環境ではこちらが推奨されます。
| コマンド | 用途 | 例 |
|---|---|---|
| apply | ファイルの内容をクラスターに適用 | kubectl apply -f deployment.yaml |
| diff | 現在の状態とファイルの差分を表示 | kubectl diff -f deployment.yaml |
命令的 vs 宣言的の使い分け
この違いは、初心者の方がつまずきやすいポイントです。イメージで覚えておきましょう。
┌─────────────────────────────────────────────────────────────────┐
│ │
│ 【命令的 (Imperative)】 │
│ │
│ 「今すぐPodを2個増やして!」と口頭で指示を出すイメージ │
│ │
│ → 手軽。学習や一時的な作業向き │
│ → 変更履歴が残らない │
│ │
│ 【宣言的 (Declarative)】 │
│ │
│ 「Podが3個動いている状態」という仕様書を提出して、 │
│ あとはKubernetesに任せるイメージ │
│ │
│ → 本番運用向き │
│ → YAMLファイルをGit管理すれば変更履歴も残る │
│ │
└─────────────────────────────────────────────────────────────────┘
通信のワークフロー
kubectlを実行した時、内部ではどんな通信が行われているのでしょうか。
エンジニアが打ったコマンドは、kubectlによってHTTPリクエストに変換され、API Serverに送られます。API Serverはetcdからデータを取得し、結果を返却します。
YAMLマニフェストの具体例(Deployment)
最後に、宣言的な管理で使うYAMLマニフェストの例を見てみましょう。
以下は「nginxコンテナを3つ維持する」というDeploymentの定義です。
# 3つのPodを維持するDeployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-webapp
spec:
replicas: 3 # ← ここに書くだけで3つ維持される
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
replicas: 3 と書くだけで、Kubernetesはこの状態を維持し続けます。
- Schedulerが最適なノードに自動配置
- Controller Managerが常に3つ維持されているか監視
- 1つ壊れたら自動で再作成(セルフヒーリング)
このように、YAMLに「あるべき姿」を書くだけで、これまで学んだ全ての機能の恩恵を受けられるのです。
Step 9: 実際の動作フロー - Podの一生を追う
ここまで学んだ全てのコンポーネントが、実際にどう連携するかを2つのシナリオで追体験しましょう。
Podがデプロイされるまでの全工程
エンジニアが kubectl apply -f deployment.yaml を実行してから、Podが起動するまでの全工程です。
セルフヒーリングの動作例
正常に動いていたPodがクラッシュした場合の自動復旧フローです。
まとめ
お疲れさまでした!ここまでの内容を振り返りましょう!
Docker vs Kubernetes 最終比較表
| 項目 | Docker / Docker Compose | Kubernetes |
|---|---|---|
| スコープ | 単一ホスト | 複数ホスト(クラスター) |
| 自動配置 | 手動 | Schedulerが自動で最適配置 |
| 自動復旧 |
restart: always(限定的) |
Controller + kubeletで自動復旧 |
| スケーリング | 手動 | HPAで自動スケール |
| 負荷分散 | 基本機能なし | Serviceで自動振り分け |
| サービス発見 | コンテナ名(同一ホスト内) | 内蔵DNS(クラスター全体) |
| 設定管理 |
.env、環境変数 |
ConfigMap / Secret |
| デプロイ | 停止→起動(ダウンタイム) | ローリングアップデート(無停止) |
| 本番運用 | 小規模なら可 | 中〜大規模の本格運用向き |
この記事で理解したこと
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ✓ Dockerは開発環境では最高。でも複数サーバーの本番運用には │
│ 自動化が不足している │
│ │
│ ✓ KubernetesはGoogleの15年の知見から生まれた │
│ コンテナオーケストレーター │
│ │
│ ✓ 4つの設計思想(自動化・宣言的・拡張性・回復力)が │
│ 全ての機能の根底にある │
│ │
│ ✓ 6つの機能(自動配置・負荷分散・自動スケール・ │
│ 自己修復・名前解決・構成管理)でDockerの限界を解決 │
│ │
│ ✓ Control Plane(脳)が判断し、Data Plane(体)が実行する │
│ │
│ ✓ kubectlでYAMLマニフェストを適用するだけで │
│ 全ての恩恵を受けられる │
│ │
└─────────────────────────────────────────────────────────────────┘
この記事が誰かのためになれば幸いです!