Certified Kubernetes Administrator (CKA) #2 クラスターアーキテクチャ 1: Control plane (apiserver/etcd/scheduler/controller-manager)

#1 試験環境 でセットアップと時間管理を固めました。ここから本題です。CKA は「クラスターがどう動くのか、壊れたらどう直すのか」を問う試験で、その答えの出発点が control plane です。control plane はクラスターの頭脳です。どの Pod をどのノードに起動するかを決め、望ましい状態と実際の状態の差を絶えず埋め、すべての変更を一か所で受けて保存します。

この記事では control plane を構成する 4 つの中核コンポーネントと cloud-controller-manager がそれぞれ何をするのか、これらがどのように static Pod として起動しているのか、そして一つずつ死んだときにクラスターにどんな症状が現れるのかを運用者の視点で解きほぐします。ここでつかむ感覚が #24 Control plane トラブルシューティング#7 etcd バックアップと復旧 の土台になります。Kubernetes の基本概念に馴染みがなければ、Kubernetes 基礎 1 編 を先に読むとこの記事がずっと入ってきやすくなります。

クラスターは control plane とノードに分かれる #

Kubernetes クラスターは大きく 2 種類のマシンに分かれます。クラスターを統制する control plane ノード と、実際のワークロード (Pod) が動く ワーカーノード です。この記事は control plane のみを扱い、ワーカーノードの kubelet と kube-proxy、CRI は #3 で続けます。

control plane がする仕事を一文で要約するとこうなります。ユーザーが宣言した 望ましい状態 (desired state) を受けて保存し、その状態を実際のクラスターに絶えず反映します。この仕事を 5 つのコンポーネントが分担します。

コンポーネント一行の役割死ぬと
kube-apiserverすべての通信の関所。認証・認可・admission を経て etcd に記録クラスターを操作できない
etcdクラスター状態を収める key-value 保存先状態を読むことも書くこともできない
kube-scheduler新しい Pod をどのノードに置くかを決定新しい Pod が Pending に留まる
kube-controller-manager複数のコントローラーを回して望ましい状態へ収束自己修復が止まる
cloud-controller-managerクラウドプロバイダー連携 (ノード・LB・ルーティング)クラウド連携が止まる

この 5 つがどう噛み合うのかを理解すれば、障害が起きたときに「どのコンポーネントの症状か」をすぐに突き止められます。試験の Troubleshooting ドメインが 30% である理由がここにあります。

kube-apiserver: すべての通信の関所 #

kube-apiserver は control plane の正門です。クラスターに対する すべてのリクエストは例外なく apiserver を経由します。kubectl コマンド、ほかの control plane コンポーネント、ノードの kubelet、コントローラーのすべてが apiserver の REST API で対話します。つまり apiserver は、クラスターで etcd に直接アクセスできる唯一のコンポーネントでもあります。残りはすべて apiserver を通してのみ状態を読み書きします。

リクエストが入ってくると、apiserver は 3 つの関所を順に通過させます。

  1. Authentication (認証)。リクエストを送った主体が誰なのかを確認します。証明書、トークン、ServiceAccount などで身元を判別します。
  2. Authorization (認可)。その主体がその動作を行う権限を持っているかを確認します。CKA では主に RBAC で決まり、#9 で深く扱います。
  3. Admission control (admission 制御)。認証・認可を通過したリクエストを実際に etcd へ書き込む前に検証または変形します。デフォルト値の注入、ポリシーの強制などがここで起こります。

この 3 つの関所をすべて通過したリクエストだけが etcd に記録されます。apiserver の動作方式と実行引数は static Pod マニフェストで確認できます。

# apiserver static Pod マニフェスト
cat /etc/kubernetes/manifests/kube-apiserver.yaml

マニフェストの command セクションには --etcd-servers--client-ca-file--authorization-mode のような中核フラグが並んでいます。CKA で apiserver が起動しない問題は、ほとんどがこのフラグや証明書パスのタイプミスから生じます。

etcd: クラスター状態の単一の真実源 #

etcd は分散 key-value 保存先であり、クラスターの すべての状態が保存される唯一の場所 です。どの Deployment があり、どの Pod がどのノードに配置されていて、どの ConfigMap と Secret があるのかが、すべて etcd に収められます。apiserver を通して私たちが作ったすべてのオブジェクトの最終到達点が etcd です。

ここから中核となる運用原則が出てきます。etcd をバックアップすれば、クラスター状態全体をバックアップすることになります。 逆に etcd が破損すると、クラスターの記憶が丸ごと消えます。だから etcd スナップショットの保存と復旧が CKA で比重を持って出題され、これは #7 が専任で扱います。

# etcd メンバー状態の確認 (証明書パスは apiserver マニフェストで確認)
ETCDCTL_API=3 etcdctl member list \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

kubeadm でインストールしたクラスターでは、etcd は control plane ノードの上に stacked の形で一緒に起動するのが既定です。可用性を高めるには、etcd を別マシンに分離した 外部 etcd cluster 構成を使い、これは #5 HA クラスター で扱います。

kube-scheduler: Pod 配置の決定 #

kube-scheduler は、まだノードが決まっていない新しい Pod を見て、どのノードに置くかを決定する コンポーネントです。ここで重要な誤解を一つ正します。scheduler は Pod を直接ノードに起動しません。scheduler がする仕事はただ 決定 だけです。適したノードを選んで Pod の nodeName フィールドを埋めるところまでが scheduler の役割で、実際にコンテナを実行するのはそのノードの kubelet です。

配置の決定は 2 段階で行われます。

  1. Filtering (フィルタリング)。Pod が要求する資源と制約条件を満たせないノードを候補から除外します。requests を満たす資源がない、taint に耐えられない、nodeSelector に合わないノードが落ちます。
  2. Scoring (スコアリング)。残った候補ノードにスコアを付けて、最も適したノードを選びます。

この決定に影響を与える nodeSelector、affinity、taints/tolerations は #13#14 で本格的に扱います。scheduler が止まると、新しい Pod はノードを割り当てられず Pending 状態 に留まります。すでに動いていた Pod は影響を受けません。

kube-controller-manager: reconciliation loop の集合 #

kube-controller-manager は、複数のコントローラーを一つのプロセスにまとめて回すコンポーネントです。各コントローラーは一つの責任を担い、望ましい状態と実際の状態を絶えず比較し、差があれば埋める ループを回します。このループを reconciliation loop と呼びます。

代表的なコントローラーは次のとおりです。

コントローラー責任
Node controllerノードが応答しないと NotReady と表示し後続処理
ReplicaSet controller指定した replica 数だけ Pod が起動しているよう維持
Deployment controllerrolling update と rollback を ReplicaSet で調律
Job controllerJob が指定回数だけ完了するよう Pod を生成
ServiceAccount/Token controller新しいネームスペースに既定の ServiceAccount を生成
Endpoints controllerService と Pod を結ぶ EndpointSlice を更新

たとえば replica が 3 の Deployment で Pod が一つ死ぬと、ReplicaSet controller が「望ましい状態 3、実際の状態 2」という差を検知し、新しい Pod を作って再び 3 に合わせます。この自己修復が controller-manager の中核的な価値です。controller-manager が止まると、これらのループがすべて停止するので、死んだ Pod が再生成されず、Deployment の変更も反映されません

cloud-controller-manager: クラウド連携の分離 #

cloud-controller-manager は、Kubernetes を特定のクラウドプロバイダーと結ぶクラウド依存ロジックを別コンポーネントとして切り出したものです。ノードが実際のクラウドインスタンスとして存在するかを確認し、LoadBalancer タイプの Service のためにクラウドロードバランサーを生成し、ノードにルーティングを設定する仕事を担います。

オンプレミスやベアメタル、そして CKA 練習用のローカルクラスターには cloud-controller-manager がないケースが多いです。クラウド連携が要らなければ、このコンポーネントも要らないからです。試験ではこういう分離の概念を理解するレベルで十分です。

static Pod として起動する control plane #

kubeadm でインストールしたクラスターでは、control plane コンポーネントは static Pod として実行されます。static Pod は apiserver や scheduler が管理しません。ノードの kubelet が特定のディレクトリのマニフェストファイルを直接読んで その Pod を実行し、管理します。そのディレクトリが /etc/kubernetes/manifests/ です。

# control plane static Pod マニフェストの一覧
ls /etc/kubernetes/manifests/
# etcd.yaml
# kube-apiserver.yaml
# kube-controller-manager.yaml
# kube-scheduler.yaml

ここに鶏と卵の問題があります。apiserver が起動していてこそ Pod を作れるのに、apiserver 自体が Pod なら、誰がそれを起動するのでしょうか。答えは kubelet です。kubelet は apiserver なしでも、このディレクトリのファイルだけを見て control plane Pod をブートストラップします。だから control plane を static Pod として置くのです。

運用の観点で最も重要な性質はこれです。kubelet はこのディレクトリを監視していて、ファイルが変わると該当の Pod を自動的に再起動します。 つまり apiserver のフラグ一つを直すには、kubectl edit ではなくこのマニフェストファイルを直接修正します。保存した瞬間に kubelet が変更を検知して Pod を再び起動します。

# 例: apiserver フラグ修正後に kubelet が自動再起動
vim /etc/kubernetes/manifests/kube-apiserver.yaml
# 保存直後に kubelet が変更を検知し apiserver Pod を再生成

ここでよくあるミスが出てきます。マニフェストの YAML インデントを誤ったり、フラグをタイプミスすると、kubelet が誤ったマニフェストで Pod を起動しようとして失敗し、apiserver 自体が上がってきません。このときは kubectl が通じないので、ノードに入って journalctl とコンテナランタイムのログで原因を追跡しなければなりません。このシナリオがまさに #24 の核心です。

static Pod にはもう一つの表示があります。static Pod は apiserver にも「ミラー Pod」として見え、名前の末尾にノード名が付きます。たとえば kube-apiserver-controlplane のように表示されます。

宣言型モデルと reconciliation #

ここまでのコンポーネントがどう協力するのかを一つの原理にまとめると、Kubernetes の核心となる哲学が見えてきます。Kubernetes は 宣言型 (declarative) モデルで動作します。ユーザーは「Pod を作れ、その次にノードに配置しろ」のような手順を指示しません。代わりに「replica 3 個があるこの Deployment が存在してほしい」という 望ましい状態だけを宣言 します。その宣言は apiserver を経て etcd に保存されます。すると scheduler と複数のコントローラーがそれぞれの reconciliation loop を回し、実際の状態をその宣言に絶えず収束させます。ノードが死んで Pod が消えるとコントローラーが再び作り、scheduler が新しいノードに配置します。ユーザーが再び介入する必要はありません。control plane を運用するということは、結局この収束ループが健全に回り続けるよう守ることなのです。

control plane コンポーネント障害の影響 #

各コンポーネントが死んだときにクラスターに現れる症状を正確に知っておくと、トラブルシューティングが速くなります。核心は、すでに動いていたワークロードと新しい操作を区別することです。

死んだコンポーネント症状すでに起動した Pod は
kube-apiserverkubectl が通じない。クラスターを読むことも変えることもできない動き続ける
etcdapiserver が状態を読み書きできず、事実上クラスター操作が不可動き続ける
kube-scheduler新しい Pod がノードを割り当てられず Pending に留まる動き続ける
kube-controller-manager自己修復が停止。死んだ Pod が未復旧、replica・Deployment 変更が未反映動き続ける
cloud-controller-manager新しい LoadBalancer Service が未生成、ノードのルーティング・整理が遅延動き続ける

表から読むべき核心は、control plane が死んでも、すでに起動している Pod は動き続ける という点です。ノードの kubelet とコンテナランタイムは control plane とは無関係に動くからです。control plane 障害は「新しい変更を受けて反映する能力」を失うことであって、現在のトラフィックを即座に切るものではありません。ただし apiserver や etcd が長く死んでいると、結局は自己修復とすべての操作が止まるので、速い復旧が必要です。

control plane 状態の確認コマンド #

CKA 試験と実務で control plane の健康状態を確認するコマンドは手に覚えておくべきです。kubeadm クラスターの control plane は kube-system ネームスペースに static Pod として起動しているので、次で一目で見ます。

# control plane コンポーネント Pod の状態
k get pods -n kube-system

# control plane コンポーネントだけ絞って見る
k get pods -n kube-system -l tier=control-plane

コンポーネントのヘルスを直接問うコマンドもあります。componentstatuses は古い API ですが、試験で今でも出くわします。

# scheduler/controller-manager/etcd ヘルス (旧 API、cs に短縮)
k get componentstatuses
k get cs

特定のコンポーネントがなぜ起動しないのかを追跡するときは、Pod ログとマニフェストを一緒に見ます。

# apiserver Pod ログ
k logs -n kube-system kube-apiserver-controlplane

# apiserver が死んで kubectl が通じないなら、ノードで直接
sudo crictl ps -a | grep apiserver
sudo journalctl -u kubelet -f

# 問題の static Pod マニフェストを直接閲覧
cat /etc/kubernetes/manifests/kube-apiserver.yaml

最後のパターンが重要です。apiserver が死ぬと k logs すら通じないので、ノードに入って crictl でコンテナを見て、journalctl で kubelet ログを追跡したうえでマニフェストを直接直す流れになります。

試験ポイント #

  • apiserver はすべての通信の唯一の関所 です。すべてのリクエストは認証・認可・admission を経て etcd に記録され、etcd に直接アクセスするコンポーネントは apiserver だけです。
  • etcd はクラスター状態の単一の真実源 です。etcd バックアップがすなわちクラスター状態のバックアップであり、etcd 復旧は #7 の核心となる出題領域です。
  • scheduler は決定だけ、kubelet が実行 します。scheduler が死ぬと新しい Pod が Pending に留まります。
  • controller-manager は reconciliation loop の集合 です。死ぬと自己修復が止まり、死んだ Pod が復旧されません。
  • control plane は /etc/kubernetes/manifests/ の static Pod です。ファイルを修正すると kubelet が自動的に Pod を再起動するので、フラグの修正はこのマニフェストを直接編集します。
  • コンポーネントが死んでも、すでに起動した Pod は動き続けます。 症状からどのコンポーネントの問題かを逆追跡する感覚がトラブルシューティングの出発点です。
  • k get pods -n kube-systemk get cscrictl ps -ajournalctl -u kubelet を手に覚えておきます。

まとめ #

この記事で押さえたこと:

  • control plane はクラスターの頭脳 です。apiserver・etcd・scheduler・controller-manager・cloud-controller-manager が役割を分担します。
  • apiserver は関所、etcd は保存先、scheduler は配置の決定、controller-manager は収束ループ、cloud-controller-manager はクラウド連携です。
  • kubeadm クラスターの control plane は /etc/kubernetes/manifests/static Pod として起動し、kubelet が直接管理してファイル変更時に自動再起動します。
  • コンポーネントごとの障害症状を知れば「どこが壊れたのか」を速く突き止められます。すでに起動した Pod は control plane 障害でも動き続けます。
  • Kubernetes は 宣言型モデル で動作し、望ましい状態を実際の状態へ収束させる reconciliation が運用の本質です。

次へ: クラスターアーキテクチャ 2 #

control plane という頭脳を見たので、ここからは実際に手足を動かす側へ下りていきます。#3 クラスターアーキテクチャ 2 では、ワーカーノードの kubelet (ノードの上で Pod を実際に実行するエージェント)、kube-proxy (Service トラフィックをルーティング)、CRI (コンテナランタイムインターフェース) がそれぞれ何をするのか、そして Pod がどのように互いに通信する Pod ネットワーキングモデルを直接覗きながら整理します。

X