Kubernetesの用語は、Cluster・Node・Pod・Containerのように似た粒度の言葉が並び、どれが何を指すのかが混ざりがちです。個別に暗記しようとすると、「NodeとPodはどう違うのか」「Control Planeはどこにいるのか」で詰まります。
この記事は、『マイクロサービスの概要まとめ』で扱った「分けたサービスを動かし続ける基盤」としてKubernetesを位置づけ、登場人物の関係を図に描ける状態を目指します。個々の機能ではなく、全体の構造を先に押さえます。
- コンテナを本番で運用し続けるのにコンテナオーケストレーションが要る理由
- Cluster・Control Plane・Node・Pod・Containerの関係
- Kubernetesがなぜ必要になるのか
前提知識:コンテナオーケストレーションとは
Kubernetesを理解するうえで、まず知っておきたいのがコンテナオーケストレーションです。その前提として、コンテナはアプリケーションと実行に必要なものをひとまとめにした実行単位です。手元で1個動かすだけなら、Dockerでdocker runすれば済みます。
ところが、コンテナを本番で運用し続けるとなると、コンテナが1個であっても、ただ動かすのとは別の考慮が出てきます。
- 落ちたコンテナを誰が再起動するのか
- アクセスが増えたとき、誰がコンテナの数を増やすのか
- 複数のマシンに、どのコンテナをどう配置するのか
- 新しいバージョンに、止めずに入れ替えるにはどうするのか
そしてマイクロサービスのようにサービスとコンテナが増えるほど、これらを人手やスクリプトで捌くのは現実的でなくなります。この「コンテナを複数マシンの上で運用し続ける」仕事を引き受けるのが、コンテナオーケストレーションであり、その代表がKubernetesです。
Kubernetesの登場人物
Kubernetesの構造は、外側から内側に向かって Cluster → Node → Pod → Container という入れ子で捉えると整理できます。これにControl Planeという「頭脳」が加わります。
flowchart TB
subgraph Cluster["Cluster(全体)"]
CP["Control Plane(頭脳)"]
subgraph Node1["Node(マシン1)"]
subgraph Pod1["Pod"]
C1["Container"]
end
subgraph Pod2["Pod"]
C2["Container"]
end
end
subgraph Node2["Node(マシン2)"]
subgraph Pod3["Pod"]
C3["Container"]
end
end
CP -->|"指示・監視"| Node1
CP -->|"指示・監視"| Node2
end
Cluster(全体)
Clusterは、Kubernetesが管理する全体のまとまりです。1つ以上のNodeと、それらを束ねるControl Planeで構成されます。「Kubernetesの環境を1つ用意する」ことは、実質的にClusterを1つ作ることです。
Control Plane(クラスタの頭脳)
Control Planeは、クラスタ全体の状態を管理する頭脳です。「このサービスをコンテナ3個で動かしたい」といった宣言を受け取り、実際のNodeの状態と突き合わせて、あるべき状態に近づけます。どのNodeにPodを配置するかを決めたり、落ちたPodを検知して立て直したりするのはこの部分の仕事です。
Control Planeは指示と監視を担当し、アプリケーションのコンテナそのものはNode側で動きます。頭脳と実働が分かれている、と捉えるとよいです。
Node(Podが動くマシン)
Nodeは、コンテナが実際に動くマシン(仮想マシンや物理マシン)です。Control Planeからの指示を受けて、割り当てられたPodを自分の上で起動・維持します。Nodeを増やせば、クラスタ全体で動かせるコンテナの量が増えます。
Pod
Podは、Kubernetesがコンテナを動かす最小単位です。1つのPodには通常1つのコンテナが入りますが、密接に連携する複数のコンテナをまとめて入れることもあります。
Kubernetesはコンテナを直接ではなくPod単位で扱います。配置・スケール・再起動といった操作はすべてPodに対して行われます。Podは使い捨ての単位で、落ちたら新しいPodとして作り直されます。このときIPアドレスも変わるため、Podを直接名指しでアクセスする設計にはしません(この点は『KubernetesのService・Ingressの関係とPodへの通信経路』で扱います)。
Container
Containerは、Podの中で実際に動くアプリケーションの実行単位です。Kubernetesは、このコンテナを直接管理するのではなく、Podという1つ外側の箱を通じて扱います。
補足: Railsアプリで見るNodeとPodの違い
Railsアプリで考えると、RailsそのものはContainerの中で動きます。Kubernetesでは、そのContainerをPodに入れて扱います。つまり記事中で「Rails Pod」と言う場合は、RailsアプリのContainerが入ったPodを指します。
flowchart TB
subgraph Node["Node(マシン)"]
subgraph Pod["Pod"]
Container["Container"]
Rails["Railsアプリ"]
Container --> Rails
end
end
Railsアプリを3つの実行単位で動かす場合、増えるのはまずNodeではなくPodです。Deploymentでreplicas: 3のように宣言すると、Railsアプリが入ったPodを3個動かす、という意味になります。
flowchart TB Service["Service(Rails Podへの安定した宛先)"] Pod1["Rails Pod"] Pod2["Rails Pod"] Pod3["Rails Pod"] Service --> Pod1 Service --> Pod2 Service --> Pod3
この3つのRails Podは、1台のNodeに全部載ることもあります。NodeにCPUやメモリの空きがあれば、複数のPodを同じNode上で動かせるためです。
flowchart TB
subgraph Node1["Node 1"]
Pod1["Rails Pod"]
Pod2["Rails Pod"]
Pod3["Rails Pod"]
end
一方で、複数のNodeに分散して載ることもあります。Nodeを複数にするのは、Podを載せる容量を増やしたり、1台のNodeが落ちても全Podが同時に落ちないようにしたりするためです。
flowchart TB
subgraph Node1["Node 1"]
Pod1["Rails Pod"]
Pod2["Rails Pod"]
end
subgraph Node2["Node 2"]
Pod3["Rails Pod"]
end
ここで大事なのは、Podを複数にすることとNodeを複数にすることは別の話だという点です。Podを複数にするのは、Railsアプリの実行単位を増やして処理を分散するためです。Nodeを複数にするのは、そのPodを載せるマシンの容量や可用性を確保するためです。
また、1つのNodeに載るPodは同じRailsアプリだけとは限りません。RailsのWebアプリ、Sidekiqのようなジョブ処理、監視用のエージェントなど、別の役割のPodが同じNodeに載ることもあります。
flowchart TB
subgraph Node["Node"]
Rails["Rails Pod"]
Sidekiq["Sidekiq Pod"]
Batch["Batch Pod"]
Agent["Monitoring Agent Pod"]
end
この場合、Rails Web、Sidekiq、監視エージェントを1セットとしてまとめて増やすのではありません。役割ごとにPodの管理方法が分かれます。
- Rails Web
- HTTPリクエストを受けるPodとして、Deploymentで台数を管理する
- Sidekiq
- ジョブを処理するPodとして、Rails Webとは別のDeploymentで台数を管理する
- 監視エージェント
- Nodeごとに1つ置きたい場合は、DeploymentではなくDaemonSetで管理することが多い
Nodeは、これらのPodを載せる共通の実行場所です。Rails Web Podを増やすか、Sidekiq Podを増やすかは役割ごとのDeploymentで決めます。Nodeを増やすのは、それらのPodを載せる容量や可用性が足りないときです。
宣言的な状態管理と自己修復
Kubernetesの中心にあるのは、宣言的な状態管理という考え方です。利用者は「何をどうしろ」という手順ではなく、「あるべき状態」を宣言します。
たとえば「このサービスはPod3個で動かす」と宣言すると、Control Planeは常に現在の状態を監視し、あるべき状態との差を埋め続けます。
- Podが1個落ちて2個になったら、1個作り直して3個に戻す
- Nodeごと落ちたら、そのNodeにいたPodを別のNodeで立て直す
この「宣言した状態に自動で収束させる」動きが、落ちても勝手に復活する自己修復の正体です。人が「落ちたから再起動する」と操作しているのではなく、あるべき状態を宣言しておけばKubernetesが差を埋め続ける、という仕組みです。
Kubernetesがなぜ必要になるのか
ここまでを踏まえると、Kubernetesが引き受けている仕事は次のように整理できます。
- スケジューリング
- どのNodeにどのPodを配置するかを決める
- 自己修復
- 落ちたPodやNodeを検知し、あるべき状態に戻す
- スケール
- 負荷に応じてPodの数を増減させる
- ロールアウト
- 新しいバージョンへ、止めずに入れ替える
これらはどれも、コンテナを1個動かすだけなら不要で、「複数サービスを複数マシンで運用し続ける」段になって初めて必要になります。マイクロサービスのようにサービス数が増えるほど、この運用を任せられる基盤の価値が上がります。
逆に、動かすものが1つのコンテナで済み、上記の運用が要らないなら、Kubernetesは過剰です。その場合の選択肢は『Cloud RunとGKEの使い分けまとめ』で扱います。
まとめ
Kubernetesの全体像は、入れ子の構造と頭脳の分離で捉えると整理できます。要点は以下です。
- Clusterが全体のまとまりで、Control Plane(頭脳)と複数のNode(実働マシン)で構成される
- Nodeの上でPodが動き、Podの中でContainerが動く。KubernetesはコンテナをPod単位で扱う
- 利用者はあるべき状態を宣言し、Control Planeが現在の状態との差を埋め続ける
- 落ちたPodが復活する自己修復は、宣言した状態に自動で収束させる仕組みの結果
- Kubernetesはスケジューリング・自己修復・スケール・ロールアウトを引き受ける。これらが要る規模になって初めて必要になる