Kubernetesの概要・全体像まとめ

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はスケジューリング・自己修復・スケール・ロールアウトを引き受ける。これらが要る規模になって初めて必要になる

参考

タグ: マイクロサービス, システム設計