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 つの関所を順に通過させます。
- Authentication (認証)。リクエストを送った主体が誰なのかを確認します。証明書、トークン、ServiceAccount などで身元を判別します。
- Authorization (認可)。その主体がその動作を行う権限を持っているかを確認します。CKA では主に RBAC で決まり、#9 で深く扱います。
- 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.keykubeadm でインストールしたクラスターでは、etcd は control plane ノードの上に stacked の形で一緒に起動するのが既定です。可用性を高めるには、etcd を別マシンに分離した 外部 etcd cluster 構成を使い、これは #5 HA クラスター で扱います。
kube-scheduler: Pod 配置の決定 #
kube-scheduler は、まだノードが決まっていない新しい Pod を見て、どのノードに置くかを決定する コンポーネントです。ここで重要な誤解を一つ正します。scheduler は Pod を直接ノードに起動しません。scheduler がする仕事はただ 決定 だけです。適したノードを選んで Pod の nodeName フィールドを埋めるところまでが scheduler の役割で、実際にコンテナを実行するのはそのノードの kubelet です。
配置の決定は 2 段階で行われます。
- Filtering (フィルタリング)。Pod が要求する資源と制約条件を満たせないノードを候補から除外します。requests を満たす資源がない、taint に耐えられない、nodeSelector に合わないノードが落ちます。
- 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 controller | rolling update と rollback を ReplicaSet で調律 |
| Job controller | Job が指定回数だけ完了するよう Pod を生成 |
| ServiceAccount/Token controller | 新しいネームスペースに既定の ServiceAccount を生成 |
| Endpoints controller | Service と 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-apiserver | kubectl が通じない。クラスターを読むことも変えることもできない | 動き続ける |
| etcd | apiserver が状態を読み書きできず、事実上クラスター操作が不可 | 動き続ける |
| 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-system、k get cs、crictl ps -a、journalctl -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 ネットワーキングモデルを直接覗きながら整理します。