← インフラ / 基盤技術

Container Orchestration / 概論

Kubernetes 航海術

なんにも知らない人のための、一冊目

Kubernetes という名前は、ギリシャ語の κυβερνήτης(クベルネーテス=舵取り、操舵手)から来ています。ロゴは船の舵輪。コンテナを積んだ船を、人間の代わりに目的地へ運び続ける仕組み ── それがこのソフトウェアの正体です。

前提知識ゼロ 図解 8 点 全 10 章 セキュリティ視点つき
あるべき状態 に収束させ続ける 観測 → 差分 → 修正
Chapter 01

なぜ Kubernetes が生まれたのか

技術は、たいてい「人間が手で回しきれなくなった」ところから生まれます。Kubernetes も例外じゃありません。まずは何がしんどかったのかから。

サーバーの単位が、どんどん小さくなった

アプリを動かす「入れ物」は、この20年でだいたい3段階に小さくなりました。

① 物理サーバー Hardware OS アプリ(1台に1つ) 調達に数週間・余った資源は捨て ② 仮想マシン Hardware Hypervisor Guest OSGuest OSGuest OS アプリアプリアプリ OSごと複製=重い・起動が分単位 ③ コンテナ Hardware Host OS (kernel) Container Runtime アプリアプリアプリアプリ カーネル共有=軽い・起動が秒/ミリ秒 粒度が細かくなるほど、1台のマシンに乗る「動くもの」の数は 10倍・100倍に増えていく。 → 数が増えた瞬間、「誰がどこに置くか」「死んだら誰が起こすか」を人間が管理できなくなる。ここが分岐点。
Fig 1-1入れ物の進化。コンテナはゲスト OS を持たず、ホストのカーネルを共有する。だから軽く、だから増える。

Noteコンテナの正体は「魔法の軽量VM」ではなく、Linux カーネルの namespace(見える範囲の分離)と cgroup(使える資源の制限)で閉じ込められた、ただのプロセスです。この事実は 8 章のセキュリティで効いてきます。

コンテナは便利、でも「数」が敵になる

Docker などでコンテナを 1 個動かすのは簡単です。問題はその先。実際のサービスは、コンテナが 3 個で済むことはまずありません。Web が 10 個、API が 20 個、バッチが 5 個、それがサーバー 8 台に散らばる。そうなると、こういう仕事が毎日発生します。

  • 配置:この新しいコンテナ、どのサーバーの空きに置く? メモリ足りてる?
  • 復旧:夜中に 1 個落ちた。誰が気づいて、誰が起こす?
  • 増減:昼にアクセスが 5 倍。手で 20 個起動して、夜に手で止める?
  • 更新:新バージョンに差し替えたい。全部同時に止めたらサービス断。1個ずつ?
  • 通信:コンテナは再起動のたびに IP が変わる。呼び出す側はどうやって見つける?
  • 秘密情報:DB のパスワード、どうやって安全に渡す?

これを全部、人間の代わりに 24 時間やってくれる係が必要になります。それがコンテナオーケストレーションで、その事実上の標準が Kubernetes(略して K8s。K と s の間に 8 文字あるから)です。

HistoryGoogle が社内で 10 年以上使っていた Borg というシステムの設計思想を受け継ぎ、2014 年に OSS 化。2015 年から CNCF(Cloud Native Computing Foundation)が管理する中立プロジェクトになりました。特定ベンダーのものではない、というのが普及した大きな理由です。

1章のまとめ

Kubernetes は「コンテナを大量に、人手をかけずに動かし続けるための自動運転システム」。逆に言うと、コンテナが数個で足りる規模なら、正直まだ要りません。

Chapter 02

世界観 ── 「宣言」と「収束」

ここが Kubernetes 最大の思想であり、最初にハマる壁です。ここさえ腹落ちすれば、残りは全部その応用になります。

命令するのではなく、宣言する

従来のサーバー管理は命令的(imperative)でした。「起動しろ」「コピーしろ」「再起動しろ」と、手順を順番に指示する。シェルスクリプトの世界です。

Kubernetes は宣言的(declarative)です。手順を指示しません。代わりに「あるべき状態(desired state)」だけを書いて渡します

やり方言い方落ちたときどうなる
命令的「このコンテナを 3 個起動しろ」1 個死んだら 2 個のまま。誰かが気づいて起こすまで放置。
宣言的「このコンテナは常に 3 個ある状態にしておいて」1 個死んだ瞬間に Kubernetes が 1 個作り直す。人間は寝てていい。

この違いは、エアコンの操作に例えるとわかりやすいです。命令的は「暖房を強で 10 分回して、止めて、また回して…」と手で調整すること。宣言的は「室温 25 ℃」と設定すること。あとは機械が測って、足りなければ働き、達したら止まる。Kubernetes はデータセンター用のサーモスタットです。

収束させ続ける ── コントロールループ

その「測って、差分を埋める」動作を reconciliation loop(調整ループ) と呼びます。Kubernetes の中身は、突き詰めるとこのループの集合体でしかありません。

あるべき状態desired state replicas: 3(人間が YAML で宣言) Controller observe → diff → act (永久に繰り返す) 差分があれば作る 差分があれば消す いまの状態current state running: 2 ← 1個落ちた(クラスタの現実) 読む監視する 重要:ループは「一度きり」ではなく永久に回り続ける。だから、あなたが手で kill したコンテナも勝手に生き返る。
Fig 2-1コントロールループ。Kubernetes に「壊れた状態」を維持させることはできない ── それが仕様。

Note「Pod を消したのに復活する!」は初心者あるある。それは Deployment が「3個」と宣言しているからで、消すべきは Pod ではなく宣言のほう(Deployment)です。

すべては API オブジェクト

では「宣言」はどこに渡すのか。Kubernetes API サーバーです。Kubernetes を使うというのは、実質的に REST API を叩いて、オブジェクトを CRUD することだと思ってください。kubectl コマンドも、Web UI も、CI/CD も、全部この API の client でしかありません。

そのオブジェクトを書く形式が YAML(マニフェスト)です。ほぼ全部のマニフェストが、この 4 つのフィールドを持ちます。

manifest の骨格

apiVersion: apps/v1 # どのAPIのバージョンで話すか kind: Deployment # 何を作るか(種類) metadata: # 名前・ラベルなどの札 name: web spec: # ★あるべき状態の中身 replicas: 3

spec が「あなたの希望」、それに対して Kubernetes が実況を書き込む status というフィールドがあります。spec と status の差分を埋めるのが Kubernetes の仕事── 2 章はこれだけ覚えて帰ってください。

2章のまとめ

手順ではなくゴールを書く。ゴールと現実の差は、コントローラーが永久ループで埋め続ける。宣言はすべて API オブジェクトとして保存される。

Chapter 03

アーキテクチャを解剖する

クラスタは「頭脳(コントロールプレーン)」と「手足(ノード)」に分かれます。登場人物は 6 つだけ。名前と役割を一度で押さえます。

Control Plane(頭脳) kube-apiserver 唯一の窓口。全ての読み書きはここを通る etcd クラスタの全状態を保存する唯一のDB kube-scheduler 新しいPodをどのノードに置くか決める kube-controller-manager 2章のループ本体。ReplicaSet/Node/Job など 数十種のコントローラーが常時ぐるぐる回っている Worker Node(手足)× N台 Node 1 kubeletノードの現場監督 kube-proxy通信の交通整理 container runtimecontainerd / CRI-O PodPodPod Node 2kubelet / kube-proxy / runtime / Pod… Node 3kubelet / kube-proxy / runtime / Pod… pull型 読み方のコツ ・ノードは apiserver に「私の担当ぶんある?」と聞きに行く(pull型)。頭脳がノードに命令をpushするのではない。 ・だから apiserver が落ちても、すでに動いている Pod は動き続ける。変更ができなくなるだけ。
Fig 3-1クラスタ全体。左が意思決定、右が実行。両者をつなぐのは常に kube-apiserver ただ一つ。

登場人物 6 人

名前置き場所仕事
kube-apiserver頭脳唯一の入口。認証・認可・検証をして etcd に書く。ここが Kubernetes の玄関であり、攻撃対象でもある。
etcd頭脳分散 KVS。全マニフェストと状態、そして Secret がここに入る。クラスタのバックアップ= etcd のバックアップ。
kube-scheduler頭脳行き先未定の Pod を見つけ、資源・制約・アフィニティを見て「ノードX」と決める。決めるだけで、起動はしない。
kube-controller-manager頭脳調整ループの集合体。「3個のはずが2個」を検知して作らせる係。
kubelet各ノード現場監督。自ノード担当の Pod 定義を受け取り、ランタイムに起動を依頼し、生死を報告する。
kube-proxy各ノードService 宛の通信を実際の Pod へ転送するルールを iptables / IPVS に書く係。

Noteマネージドサービス(EKS / GKE / AKS)を使うと、左半分(コントロールプレーン)はクラウド事業者が運用してくれて、あなたはノードだけ気にすればよくなります。最初はこれが圧倒的に楽です。

kubectl apply を押してから Pod が動くまで

全体像が入ったところで、1 本の流れを追ってみましょう。ここが繋がると一気に「わかった」感が出ます。

1kubectl applyYAMLをPOST 2apiserver認証→認可→検証 3etcd に保存この時点で「宣言」成立 4controllerPodを作れと登録 5schedulerNode2 に決定 6kubelet が起動runtimeへ依頼 ※ 4〜6 はそれぞれ独立したループ。誰も互いに直接命令せず、全員が apiserver 経由で「変化を watch」して勝手に動く。 この疎結合が Kubernetes の拡張性の源。だから Operator(9章)で自作の登場人物を追加できる。
Fig 3-2apply の旅。各コンポーネントは互いを知らず、API サーバー上の状態変化だけを見て動く。
3章のまとめ

頭脳= apiserver / etcd / scheduler / controller-manager、手足= kubelet / kube-proxy。全員の会話は必ず apiserver を経由する。etcd はクラスタの記憶そのもの。

Chapter 04

オブジェクト図鑑

Kubernetes を覚えるとは、結局この「オブジェクトの種類(kind)」を覚えることです。よく使う 12 種を、役割ごとに。

Pod ── 最小単位

Kubernetes はコンテナを直接扱いません。必ず Pod という箱に入れて扱います。Pod は 1 個以上のコンテナのグループで、中のコンテナは同じ IP・同じ localhost・同じボリュームを共有します。つまり Pod の中は「1台のマシンの中」のような世界です。

基本は「1 Pod = 1 コンテナ」。2 個目を同居させるのは、本体と一心同体で動く補助役(ログ収集・プロキシなど、いわゆる サイドカー)を入れるときだけです。

NotePod は使い捨てです。壊れたら直さず、捨てて新しく作る。IP も名前も変わる。この「家畜であってペットではない(cattle, not pets)」感覚が、従来のサーバー運用との一番大きな精神的ギャップです。

Deployment ── 実務で一番書くやつ

Pod を直接作ることは、実務ではほぼありません。死んだら復活しないからです。代わりに Deployment を書きます。階層はこうなっています。

Deployment「v2 のアプリを 3 個」+更新のやり方を宣言 ReplicaSet (v2)「同じ Pod を常に 3 個」だけを担当 ReplicaSet (v1)旧世代。0個に縮められ、履歴として残る ← rollout undo でここに戻せる Pod10.1.2.7 Pod10.1.4.3 Pod10.1.9.5 世代を作る 数を保つ Deployment=「世代管理」担当、ReplicaSet=「頭数」担当、という分業。 だからバージョンを変えると新しい ReplicaSet が生まれ、古いほうが縮む。
Fig 4-1Deployment → ReplicaSet → Pod。あなたが書くのは一番上だけ。下の 2 段は自動で生まれる。

deployment.yaml ── 実務で最初に書くファイル

apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 3 # 何個ほしいか selector: matchLabels: {app: web} # どのラベルのPodを自分の管轄とみなすか template: # ここから下が「Podの設計図」 metadata: labels: {app: web} # ↑selectorと一致させること(重要) spec: containers: - name: nginx image: nginx:1.27 # latestは使わない(何が動くか不定になる) ports: [{containerPort: 80}] resources: # 7章で解説。書かないと事故る requests: {cpu: "100m", memory: "128Mi"} limits: {cpu: "500m", memory: "256Mi"}
最重要概念:ラベルとセレクタ

Kubernetes のオブジェクト同士は、ID で紐づいていません。「ラベル(付箋)」と「セレクタ(付箋の検索条件)」というゆるい関係だけで繋がっています。Deployment は app=web という付箋の付いた Pod を数え、Service は同じ付箋の Pod へ通信を配ります。
この仕組みのおかげで柔軟なのですが、ラベルのタイプミス=どこにも繋がらない、が最頻出の事故でもあります。

Service ── 変わり続ける IP に、固定の住所を与える

Pod は死んで生き返るたびに IP が変わります。呼ぶ側が追いかけるのは不可能。そこで Service が、その集団に安定した仮想 IP と DNS 名を与えて、届いた通信をラベルの合う Pod に振り分けます。Kubernetes 内蔵のロードバランサだと思ってください。詳しくは 5 章で。

設定と秘密 ── ConfigMap / Secret

設定値をイメージに焼き込むと、環境ごとにイメージを作り直すハメになります。だから外に出します。

  • ConfigMap:設定値(URL、フラグ、設定ファイルそのもの)。環境変数かファイルとして Pod に渡す。
  • Secret:パスワード、API キー、証明書。使い方は ConfigMap とほぼ同じ。
Secret の誤解

Secret の中身は base64 エンコードされているだけで、暗号化ではありませんbase64 -d で誰でも読めます。デフォルトでは etcd にもほぼ平文で載ります。「Secret に入れたから安全」は完全な誤解で、実際には etcd の保存時暗号化・RBAC による閲覧制限・外部の秘密管理(Vault や各クラウドの Secrets Manager)との連携が要ります(8 章)。

そのほかの主要な kind

kindひとことで使いどころ
Namespaceクラスタ内の仕切りチーム別・環境別に名前空間を分ける。権限や割当量の単位にもなる。
IngressHTTP の玄関外部からの HTTP(S) を、パスやホスト名でどの Service に流すか決める。TLS 終端もここ。
PersistentVolumeClaim永続ディスクの要求書「10GiB の読み書き可能なディスクをくれ」と宣言すると、実体(PV)が用意され Pod にマウントされる。
StatefulSet個体識別ありの DeploymentDB や Kafka など、Pod ごとに固有名と固有ディスクが要るもの。web-0, web-1 と番号が固定される。
DaemonSet全ノードに1個ずつログ収集エージェント、監視エージェント、EDR、CNI プラグインなど。ノードが増えたら自動で1個追加される。
Job / CronJob使い捨ての処理 / 定期実行バッチ、マイグレーション、定時集計。完了したら終わる(=常駐しない)。
HorizontalPodAutoscaler自動増減CPU 使用率などを見て replicas を自動で上下させる(7章)。
NetworkPolicyPod 用ファイアウォールどの Pod がどの Pod と話してよいかを制限する(8章)。
ServiceAccountPod 自身の身分証Pod が Kubernetes API を叩くときの identity。RBAC と対で使う(8章)。
4章のまとめ

Pod は使い捨ての最小単位。人間が書くのは Deployment。オブジェクト同士はラベルというゆるい紐で繋がる。Secret は暗号化ではない。

Chapter 05

ネットワーク ── どうやって届くのか

Kubernetes で一番わかりにくいのがネットワークです。でも大原則は 3 行で言えます。

3 つの大原則

  1. すべての Pod は固有の IP を持つ(コンテナごとではなく Pod ごと)
  2. すべての Pod は、ノードをまたいでも NAT なしで直接通信できる(=クラスタ全体が一つのフラットな LAN に見える)
  3. この「平らな LAN」を実際に作るのは Kubernetes 本体ではなく、CNI プラグイン(Calico、Cilium、Flannel など)という差し替え可能な部品

Docker に慣れていると「ポートフォワードは?」となりますが、Kubernetes ではその発想が要りません。Pod 同士は最初から直接話せます。問題は「相手の IP がコロコロ変わる」ことだけ。それを解決するのが Service です。

User https://shop.example.com/api Ingressホスト名・パスで振り分け Service: apiClusterIP 10.96.0.21 Service: webClusterIP 10.96.0.35 Pod app=apiPod app=api Pod app=webPod app=web ラベルの合うPodへ負荷分散 Service の 3 タイプ ── 「どこから見えるか」の違いだけ ClusterIP(既定) クラスタの中からだけ見える 用途:内部サービス間通信 DNS: api.default.svc.cluster.local NodePort 全ノードの高位ポートを開ける 用途:検証・LBがない環境 例: <NodeIP>:30080 LoadBalancer クラウドのLBを自動で払い出す 用途:本番の外部公開 L4。HTTPのルーティングはIngressの仕事
Fig 5-1外→内の経路と、Service の 3 タイプ。Ingress は L7(HTTP・TLS終端)、Service は L4 と覚えると整理しやすい。

名前で呼べる ── クラスタ内 DNS

クラスタには DNS(CoreDNS)が内蔵されていて、Service を作ると自動で名前が登録されます。だからアプリのコードには IP ではなく名前を書けます。

# 同じ Namespace なら短い名前でいい http://api:8080/users # 別 Namespace なら .名前空間 を足す http://api.production:8080/users # 正式名(FQDN) http://api.production.svc.cluster.local:8080/users

Note「Service の ClusterIP」は、実はどのネットワークインターフェースにも存在しない仮想 IPです。各ノードの kube-proxy が iptables / IPVS にルールを書いて、その宛先を実 Pod の IP へ書き換えているだけ。だから ping は通らないのに通信はできる、という状況が起こります。

Ingress、そしてその後継

Service(LoadBalancer)を公開したい URL の数だけ作ると、クラウドの LB がその数だけ生えて高くつきます。Ingress は「1 つの入口で受けて、ホスト名やパスで内部の Service に振り分ける」ための仕組みです。実体としては NGINX や Traefik などの Ingress Controller を別途インストールして使います。

なお近年は、より表現力の高い後継仕様 Gateway API への移行が進んでいます。新規で学ぶなら「Ingress が今の主流、Gateway API が次」という位置づけで覚えておけば十分です。

5章のまとめ

Pod は全員フラットに直接通信できる。IP が動くので Service で固定の名前と仮想 IP を被せる。外部公開は L4 なら LoadBalancer、HTTP なら Ingress。

Chapter 06

実際に触ってみる(kubectl)

概念だけ読んでも身体に入りません。ノート PC 1 台で完結する手順を置いておきます。

手元にクラスタを立てる

本物のサーバーは要りません。Docker さえ入っていれば、以下のどれかで 1 コマンドです。

ツール特徴起動
kindDocker コンテナ自体をノードにする。軽くて速い。CI 向き。kind create cluster
minikubeアドオンが豊富で入門向き。ダッシュボードも付く。minikube start
Docker Desktop設定画面のチェックひとつで有効化できる。Settings → Kubernetes

最初の 10 分

起動から公開・確認・削除まで

# 1. クラスタを作る $ kind create cluster --name lab # 2. ノードが見えるか(接続確認) $ kubectl get nodes NAME STATUS ROLES AGE VERSION lab-control-plane Ready control-plane 40s v1.31.0 # 3. さっきの deployment.yaml を適用する(=宣言する) $ kubectl apply -f deployment.yaml deployment.apps/web created # 4. 望んだ状態に収束したか見る $ kubectl get pods -o wide NAME READY STATUS RESTARTS IP NODE web-6c9f8d7b4-2xqzp 1/1 Running 0 10.244.0.6 lab-control-plane web-6c9f8d7b4-8vkrm 1/1 Running 0 10.244.0.7 lab-control-plane web-6c9f8d7b4-p4t9c 1/1 Running 0 10.244.0.8 lab-control-plane # 5. 1個わざと殺してみる ← ここが感動ポイント $ kubectl delete pod web-6c9f8d7b4-2xqzp $ kubectl get pods # 数秒後、別名のPodが生えて再び3個になっている # 6. 内部向けに公開して、ブラウザで見る $ kubectl expose deployment web --port=80 --name=web-svc $ kubectl port-forward svc/web-svc 8080:80 # → http://localhost:8080 # 7. 片付け $ kubectl delete -f deployment.yaml $ kind delete cluster --name lab

Tipsalias k=kubectl はほぼ全員が入れています。あわせて kubectl completion による補完と、コンテキスト/Namespace を切り替える kubens / kubectx を入れると生存率が上がります。

覚えるべきコマンドは、実質これだけ

コマンド意味いつ使う
kubectl get <kind>一覧を見る常に。-A で全 Namespace、-w で変化を追跡。
kubectl describe <kind> <name>詳細+イベント履歴Pod が起動しない時の第一手。末尾の Events に理由が出る。
kubectl logs <pod>標準出力を見るアプリのエラー調査。-f で追尾、--previous でクラッシュ前の分。
kubectl exec -it <pod> -- sh中に入るデバッグ。ただし本番での常用は非推奨。
kubectl apply -f <file>宣言を反映作成も更新も同じコマンド。これが宣言的ということ。
kubectl get <kind> <name> -o yaml実際の状態を YAML でKubernetes が補完した既定値や status を読む学習に最適。
kubectl explain <kind>.specフィールドの説明公式ドキュメントを引かずに済む隠れた名コマンド。
よく出る STATUS の読み方

ImagePullBackOff=イメージ名かレジストリ認証の誤り。CrashLoopBackOff=コンテナが起動直後に落ちるのを繰り返している(logs --previous を見る)。Pending=置くノードがない(資源不足かスケジュール制約)。OOMKilled=メモリ上限超過で強制終了。

6章のまとめ

kind か minikube で 1 分でクラスタは作れる。getdescribelogs の 3 段で、トラブルの 9 割は原因まで辿り着ける。

Chapter 07

運用 ── 落とさず、増やし、直す

Kubernetes を導入する実利は、ほぼこの章に集まっています。無停止更新・自動復旧・自動増減。

無停止で更新する(ローリングアップデート)

Deployment の image を書き換えて apply するだけで、Kubernetes は新しい Pod を 1 つ作り、健康を確認してから、古い Pod を 1 つ消すという入れ替えを、サービスを止めずに繰り返します。

時間 → t0t1t2t3 v1v1v1 v1v1v1v2 起動中 v1v2v2 v2v2v2 正常稼働(3個とも旧版) 新版を1個追加(一時的に4個)。まだ通信は流さない=Readiness待ち 新版がReadyになったら、旧版を1個落とす。以降くり返し 入れ替え完了。この間ずっと利用可能なPodは3個前後を維持 maxSurge(一時的に超過してよい数)と maxUnavailable(欠けてよい数)で、入れ替えの激しさを調整できる。 失敗に気づいたら kubectl rollout undo で旧 ReplicaSet に即座に戻せる(4章 Fig 4-1 の点線)。
Fig 7-1ローリングアップデート。無停止デプロイが「設定不要の標準機能」なのが Kubernetes の大きな価値。

健康診断(Probe)── 自動復旧の要

Kubernetes が「この Pod は生きている」と判断する基準は、あなたが教える必要があります。プロセスが残っていても、中でデッドロックしていれば無意味だからです。

Probe問い失敗すると
livenessProbe「まだ生きてる?」コンテナを再起動する
readinessProbe「もう客を捌ける?」Service の振り分け先から外す(再起動はしない)
startupProbe「起動終わった?」起動が遅いアプリを liveness の誤爆から守る
livenessProbe: httpGet: {path: /healthz, port: 8080} initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: {path: /ready, port: 8080} # DB接続が確立してから200を返す設計にする

Notereadiness を書かないと、まだ起動途中の Pod に本番トラフィックが流れ込み、ローリングアップデートのたびに一瞬 500 が出ます。「デプロイすると数秒エラーが出る」の原因はだいたいこれ。

資源の宣言(requests / limits)

  • requests:「最低これだけ必要」。スケジューラはこの値だけを見て配置を決めます。実使用量ではありません。
  • limits:「これ以上は使わせない」。CPU は超えると絞られ(throttling)、メモリは超えると即 kill(OOMKilled)されます。

これを書かない Pod は、ノードのメモリを食い尽くして隣の無関係な Pod を巻き込んで落とすことがあります。マルチテナントなクラスタでは、Namespace 単位で ResourceQuota / LimitRange を敷いて強制するのが定石です。

自動で増減させる(HPA)

$ kubectl autoscale deployment web --min=3 --max=20 --cpu-percent=70

これで CPU 使用率が 70% を超えたら Pod が増え、下がれば減ります(metrics-server が必要)。さらに Pod を置くノード自体が足りなくなったら、Cluster AutoscalerKarpenter がクラウドの VM 自体を増やします。「Pod のオートスケール」と「ノードのオートスケール」は別レイヤーの別部品、というのは混同しやすいポイントです。

7章のまとめ

更新は Deployment が段階的にやる。復旧は Probe の設計次第。配置と巻き込み事故の防止は requests / limits 次第。オートスケールは Pod 用とノード用の 2 段。

Chapter 08

セキュリティ ── 攻撃面の地図

Kubernetes は「デフォルトが安全」ではありません。何もしなければ、Pod 同士は全通信できて、Secret は素通しで、コンテナから外に出られる設定すら書けてしまいます。

① kube-apiserver 匿名アクセス・過剰なRBAC 奪取=クラスタ全体の掌握 ② etcd (2379) 全Secretが実質平文で常駐 直接読めれば認証を丸ごと窃取 ③ kubelet API (10250) 未認証だと任意コンテナで exec=ノード上でRCE相当 ④ コンテナ実行設定 privileged / hostPath / hostPID → ホストへの脱出経路 ⑤ ServiceAccount トークン Podに自動マウントされる → 侵入後の権限昇格の踏み台 ⑥ Pod間ネットワーク 既定で全Pod相互通信が可能 → 侵入後の横展開が容易 ⑦ 供給網 公開イメージ の脆弱性 改ざん・ typosquatting 署名/SBOMで 検証する 最初に打つべき手(費用対効果の高い順) 1. RBAC を最小権限に 2. NetworkPolicy で既定拒否 3. Pod Security Standards を restricted に 4. etcd の保存時暗号化+外部Secret管理 5. 監査ログ有効化 6. イメージスキャンをCIに組み込む ※ 1〜3 は Kubernetes 標準機能だけで今日からできる。
Fig 8-1攻撃面の地図。①〜③は「露出させない」、④〜⑥は「既定値を締める」、⑦は「入れる前に検証する」。

RBAC ── 誰が何をしてよいか

Kubernetes の認可は RBAC(Role-Based Access Control) です。構造はシンプルで、4 つのオブジェクトの組み合わせだけです。

  • Role(Namespace 内)/ ClusterRole(クラスタ全体)= 許可する動詞と対象(例:podsget, list
  • RoleBindingClusterRoleBinding = その Role を「誰に」割り当てるか(ユーザー、グループ、ServiceAccount)
アンチパターン

面倒だからと cluster-admin を ServiceAccount に ClusterRoleBinding してしまう。これは「その Pod を取られたら即クラスタ全掌握」を意味します。kubectl auth can-i --list --as=system:serviceaccount:default:myapp で、実際に何ができるのかを必ず確認してください。

NetworkPolicy ── 既定は「全許可」であることを知る

5 章で見たとおり、Pod は全員フラットに通信できます。これは裏を返せば、1 つの Pod を踏まれたら、そこから DB Pod にも管理系 Pod にも自由に到達できるということです。NetworkPolicy を 1 枚も置いていないクラスタは、内部が完全にフラットな LAN と同じです。

まず入れるべき「既定拒否」ポリシー

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: {name: default-deny-ingress, namespace: production} spec: podSelector: {} # この名前空間の全Podが対象 policyTypes: [Ingress] # 入ってくる通信を既定で拒否 → 必要な経路だけ個別に開ける

NoteNetworkPolicy を実際に適用するのは CNI プラグインです。CNI が非対応だと、マニフェストを書いても静かに無視されます(=守れているつもりで守れていない)。Calico や Cilium ならまず問題ありません。

コンテナからホストへ ── 脱出の温床になる設定

1 章で触れたとおり、コンテナは分離されたプロセスにすぎません。次の設定は、その分離を自ら壊すものです。

設定何が起きるか
privileged: trueほぼ全ての capability とデバイスアクセス。実質ホスト root への直行便。
hostPath マウントホストの / や docker.sock をマウントできてしまう。docker.sock を取られたら終わり。
hostNetwork / hostPIDホストのネットワーク名前空間・プロセス空間が丸見えになる。
runAsUser: 0コンテナ内 root。脱出時の起点として有利になる。

これらを組織的に禁止する標準機能が Pod Security Standardsprivileged / baseline / restricted の 3 段階)です。Namespace にラベルを 1 行貼るだけで強制できます。より細かい条件を書きたい場合は、OPA GatekeeperKyverno といったポリシーエンジンを Admission Webhook として挟みます。

$ kubectl label namespace production \ pod-security.kubernetes.io/enforce=restricted

防御側として押さえるチェックリスト

  • 監査ログ(Audit Log)を有効化し、SIEM に送る。誰がいつ何の API を叩いたかは、ここにしか残らない。
  • ServiceAccount トークンの自動マウントを切るautomountServiceAccountToken: false)。API を叩かない Pod に身分証を持たせない。
  • イメージは固定タグではなくダイジェスト@sha256:...)で指定し、CI で脆弱性スキャンと署名検証(cosign / Sigstore)を通す。
  • ランタイム検知:Falco や eBPF ベースの製品で、コンテナ内の異常な exec・シェル起動・想定外の外向き通信を検知する。
  • ベンチマーク:CIS Kubernetes Benchmark を kube-bench で、権限設定の穴を kubectl-who-canrbac-tool で定期点検する。
8章のまとめ

Kubernetes の既定値は「利便性寄り」。RBAC 最小化・NetworkPolicy 既定拒否・Pod Security Standards の 3 つは、標準機能だけで今日から締められる。Secret は暗号化されていないという事実から目を逸らさないこと。

Chapter 09

周辺エコシステム

Kubernetes 単体で完結する現場はほぼありません。周りに何がいるのか、地図だけ持っておきます。

マニフェストが増えすぎる問題 ── Helm と Kustomize

YAML は環境(開発/検証/本番)ごとに微妙に違うだけの、ほぼ同じファイルが量産されがちです。その解決策が 2 つあります。

ツール考え方向いている場面
HelmYAML をテンプレート化し、変数(values.yaml)を注入する。「Kubernetes 版パッケージマネージャ」他人が作ったミドルウェア(Prometheus、Nginx Ingress など)を1コマンドで入れる。配布する。
Kustomizeベースの YAML に対して差分(パッチ)を重ねる。テンプレート言語を使わない。kubectl に内蔵。自社アプリの環境差分を管理する。素の YAML のままでいたい場合。

Kubernetes を拡張する ── CRD と Operator

3 章で見たとおり、Kubernetes は「API サーバー+ループを回す人」の集合でした。ならば自分で新しい kind を追加し、自分でループを書けばいい ── これが CRD(Custom Resource Definition)Operator です。

たとえば PostgreSQL Operator を入れると、kind: PostgresCluster という自作の種類が使えるようになり、バックアップやフェイルオーバーといった「運用担当者の知識」までコードとしてループに組み込めます。Kubernetes が単なるコンテナ実行基盤を超えて「あらゆる運用の共通プラットフォーム」と呼ばれるのは、この拡張性が理由です。

GitOps ── Git が唯一の正

宣言的であるということは、「あるべき状態」が全部ファイルであるということ。ならばそれを Git に置き、Git の内容とクラスタの状態を突き合わせて自動で収束させるのが自然です(2 章のループを、クラスタの外にもう一段かけるイメージ)。Argo CDFlux がその役目を担います。人が本番に kubectl apply しなくなるので、変更履歴と承認が Git の Pull Request に一本化される ── 監査の観点でも強力です。

そのほか、名前だけ知っておくと会話に困らないもの

領域代表格役割
マネージド K8sEKS / GKE / AKSコントロールプレーンを事業者が運用。実務のスタートは基本これ。
可観測性Prometheus + Grafana / OpenTelemetry / Lokiメトリクス・トレース・ログ。Pod は消えるので、外に出して保存するのが前提。
サービスメッシュIstio / Linkerd / CiliumPod 間通信の mTLS 暗号化、細かいトラフィック制御、通信の可視化。
Secret 管理External Secrets Operator / Vault / SOPS本物の秘密は外部で管理し、必要な時だけ注入する。
ポリシー / セキュリティKyverno / Gatekeeper / Falco / Trivy入れる前に止める(Admission)、動いてから気づく(Runtime)、事前に見つける(Scan)。
ローカル開発kind / minikube / k3s手元・エッジ・IoT 機器向けの軽量ディストリビューション。

NoteCNCF の全体図(Cloud Native Landscape)には数百のプロダクトが並んでいて、初見では確実に酔います。あれは「カタログ」であって「必修リスト」ではありません。必要になってから 1 つずつ引けば十分です。

Chapter 10

次の一歩と用語集

ここまでで概観は終わりです。最後に、手を動かす順番と、詰まったとき用の索引を置いておきます。

おすすめの学習順

  1. kind でクラスタを立てて、6 章の 10 分コースをそのまま実行する。特に「Pod を消して復活を見る」ところまで必ずやる。理屈より先に、この一回の体験が効きます。
  2. 自分の書いた小さな Web アプリをコンテナ化して載せる。Deployment + Service + Ingress の 3 枚だけ書く。ここで大抵 ImagePullBackOffCrashLoopBackOff に出会えるので、describelogs の練習になります。
  3. ConfigMap / Secret / Probe / resources を足していく。1 つずつ足しては壊し、kubectl explain でフィールドを引く。
  4. 意図的に壊して観察する。ノードを止める、メモリ制限を極端に下げて OOMKilled を起こす、readiness を落として Service から外れる様子を見る ── 復旧の挙動を目で確認すると、2 章のループが腹落ちします。
  5. セキュリティを締める。NetworkPolicy で既定拒否にして通信が切れることを確認し、必要な穴だけ開ける。RBAC を絞って can-i で検証する。

資格を軸にするなら、実技試験の CKA(管理者)/CKAD(開発者)/CKS(セキュリティ)があります。特に CKS は 8 章の内容をそのまま実技で問う試験なので、学習の地図として優秀です。

用語集

用語意味
クラスタコントロールプレーン+ノード群からなる、Kubernetes の1単位。
マニフェストあるべき状態を書いた YAML ファイル。船荷証券(manifest)が語源。
desired state / current state宣言した状態と、実際の状態。この差を埋めるのが Kubernetes の全仕事。
コントロールループobserve → diff → act を永久に繰り返す仕組み。Kubernetes の心臓。
ラベル / セレクタオブジェクトに貼る付箋と、その検索条件。オブジェクト同士の唯一の接着剤。
Namespaceクラスタ内の論理的な仕切り。権限・割当量・DNS 名の単位。
CNIPod にネットワークを提供する差し替え可能なプラグイン規格(Calico、Cilium 等)。
CRIkubelet とコンテナランタイムの間の規格(containerd、CRI-O)。
CSIストレージを接続するための規格。クラウドのディスクなどを PV として繋ぐ。
Admission WebhookAPI サーバーが etcd に書く直前に、外部に検証や書き換えをさせる拡張点。ポリシー強制の要。
CRD / Operator独自の kind を追加する仕組み/その面倒を見る自作コントローラー。
Taint / Tolerationノード側の「立入禁止札」と、Pod 側の「立ち入り許可証」。配置制御に使う。
Drain / Cordonノードのメンテ前に Pod を退避させる/新規配置を止める操作。
cattle, not pets個体を大事に治すのではなく、壊れたら捨てて作り直すという運用思想。
最後に ── 導入しないという選択

Kubernetes は強力ですが、複雑さも本物です。運用するチームが小さい、コンテナが数個で足りる、といった状況では、素の VM やマネージドなコンテナ実行基盤(Cloud Run、ECS/Fargate、App Service 等)のほうが幸せなことは普通にあります。「Kubernetes は解くべき問題があるときにだけ効く薬」── この距離感を持っておくと、技術選定でも会話でも強いです。