Skip to content
Published on

Kubernetes 内部構造 完全ガイド — etcd, API Server, Controller, Scheduler, kubelet, CRI/CNI/CSI ディープダイブ (2025)

Authors

はじめに — Kubernetes は単なるツールではない

kubectl apply -f deployment.yaml。この一行でコンテナがどこかのノードに配置され、死ねば再起動され、トラフィックが分散され、ローリング更新が進行する。これが Kubernetes の約束である。

その裏には、etcd の分散合意、kube-apiserver の watch プロトコル、Scheduler のビンパッキング、Controller の reconciliation ループ、kubelet の Pod ライフサイクル、CRI/CNI/CSI プラグインインターフェースがある。これらが協調して「宣言的インフラ」という抽象を作り上げる。

本稿は Linux インフラシリーズの最終回である。


1. Kubernetes とは何か

Kubernetes は、ユーザーが宣言した desired state に向かってクラスタを永遠に収束させる分散システムである。

キーワードは 宣言的 (declarative)収束 (convergence)分散 (distributed)

1.1 宣言的

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25

「何をすべきか」を宣言し、「どうやって」は Kubernetes が決める。

1.2 収束

desired state と actual state が一致しないとき、Controller が差分を埋める。これが reconciliation loop。Pod を削除すれば Controller が再作成する。

1.3 分散

control plane (etcd + Raft) も data plane も分散している。1 ノード落ちてもクラスタは動く。


2. 歴史 — Borg から Kubernetes 1.30 まで

  • Borg (2003-): Google 内部のクラスタ管理システム。Job, Task, Cell, Borgmaster, Borglet。毎分数百万 task を 90%+ 稼働で処理。
  • Omega (2013): shared-state モデルで multiple scheduler をサポート。Kubernetes のアーキテクチャの着想源。
  • Kubernetes (2014): Joe Beda, Brendan Burns, Craig McLuckie 主導。Go、オープンソース、REST リソース。1.0 は 2015 年。
  • CNCF (2015): 初の卒業プロジェクト。
  • マイルストーン: 1.5 (StatefulSet, CRI), 1.7 (RBAC stable), 1.24 (Docker shim 削除), 1.30 (Pod scheduling readiness, AppArmor stable)。

マネージド: EKS, GKE, AKS, DOKS, LKE。ディストリビューション: OpenShift, Rancher, Tanzu, k3s, kubeadm。

★ Insight ─────────────────────────────────────

  • Borg と Kubernetes の非対称性: Google は両方を運用し、Borg を Kubernetes に移行しない。オープンソース化とコード公開は別物。
  • Omega を単純化: Kubernetes は etcd を single source of truth とし、全コンポーネントが watch する形に整理。
  • alpha -> beta -> stable は年単位。production 採用前に安定度を確認すること。 ─────────────────────────────────────────────────

3. アーキテクチャ — Control Plane と Data Plane

3.1 Control Plane

  • etcd: 分散 KV。クラスタ状態のすべてを保持。
  • kube-apiserver: REST インターフェース。etcd への唯一の経路。
  • Controller Manager: 多数の Controller を実行。
  • Scheduler: Pod をノードに割り当て。
  • Cloud Controller Manager: クラウド連携。

3.2 Data Plane

  • kubelet: 各ノードのエージェント。
  • kube-proxy: ノード単位のネットワークプロキシ。
  • コンテナランタイム: containerd, CRI-O。

3.3 Pod 作成フロー

  1. kubectl が YAML を kube-apiserver に POST。
  2. kube-apiserver が認証・認可・admission を実行し、etcd に保存。
  3. Scheduler が未スケジュール Pod を watch で発見し、ノードを選択。
  4. kubelet がそのノードで Pod を watch し、CRI にコンテナ作成を依頼。
  5. CRI がコンテナを起動し、CNI がネットワークを設定。
  6. kubelet が Pod 状態を kube-apiserver に報告。

原則: コンポーネント同士の直接通信はない。すべて kube-apiserver 経由。疎結合・single source of truth・監査が一元化。代償として kube-apiserver と etcd がボトルネックになり得る。


4. etcd — 土台

4.1 概要

CoreOS が作った分散 KV (名前は /etc + d)。現在は CNCF プロジェクト。

特徴: 分散 (Raft)、linearizable、watch、transaction、TTL lease。

4.2 Raft

リーダーが書き込みをさばき、follower にログを複製。過半数 ack で commit。3 ノードで 1 障害、5 ノードで 2 障害まで許容。

4.3 Kubernetes における etcd

すべてのオブジェクトを以下のようなキーで保存。

/registry/pods/default/my-pod
/registry/services/default/my-service

Protobuf でエンコード (以前は JSON)。

4.4 Watch

クライアントが prefix を watch するとイベントストリームを受け取る。kube-apiserver の watch の基礎。

4.5 制約

  • オブジェクトサイズ上限 ~1.5MB。
  • 約 10K writes/sec が上限。
  • 全データを mmap でメモリに。
  • Secret ローテーションはコスト高。

4.6 運用

etcdctl snapshot saveetcdctl defrag、リーダー変更頻度・fsync レイテンシの監視。etcd を壊すとクラスタが丸ごと壊れる。


5. kube-apiserver — ハブ

5.1 役割

REST API、認証、認可、admission control、watch 配信、etcd アクセス。

5.2 REST モデル

GET    /api/v1/namespaces/default/pods
POST   /api/v1/namespaces/default/pods
PUT    /api/v1/namespaces/default/pods/my-pod
DELETE /api/v1/namespaces/default/pods/my-pod

API group: core/v1, apps/v1, batch/v1, networking.k8s.io/v1, rbac.authorization.k8s.io/v1。

5.3 認証

X.509 証明書、ServiceAccount token、OIDC bearer token、webhook。複数併用可。

5.4 認可 — RBAC

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

5.5 Admission Control

Mutating (デフォルト補完) と Validating (拒否可)。内蔵: LimitRanger、ResourceQuota、PodSecurity、ServiceAccount。Dynamic Admission Webhook で cert-manager や Istio injector が動く。

5.6 Watch と Informer

GET /api/v1/pods?watch=true
< event: ADDED, pod: ...
< event: MODIFIED, pod: ...

List + Watch の標準パターン (informer):

informer := factory.Core().V1().Pods().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) { /* ... */ },
    UpdateFunc: func(old, new interface{}) { /* ... */ },
    DeleteFunc: func(obj interface{}) { /* ... */ },
})
informer.Run(stopCh)

5.7 API 拡張

CRD (主流) または API aggregation (metrics-server 方式)。


6. Scheduler — Pod とノードのマッチング

6.1 フロー

未スケジュール Pod を watch -> ノードを filter -> 残りを score -> 最高点を選択 -> spec.nodeName を更新。

6.2 Filter

NodeResourcesFit、NodeAffinity、PodAffinity/AntiAffinity、TaintToleration、VolumeBinding、PodTopologySpread。

6.3 Score

NodeResourcesBalancedAllocation、NodeResourcesLeastAllocated、InterPodAffinity。

6.4 プラグインインターフェース

type FilterPlugin interface {
    Filter(ctx context.Context, state *CycleState, pod *Pod, nodeInfo *NodeInfo) *Status
}

type ScorePlugin interface {
    Score(ctx context.Context, state *CycleState, pod *Pod, nodeName string) (int64, *Status)
}

6.5 ビンパッキング

greedy。最適ではない。Descheduler が evict で再配置を誘導する。

6.6 Custom Scheduler

複数 Scheduler を同居可。Pod の spec.schedulerName で選択。


7. Controller Manager — 収束のエンジン

7.1 Controller パターン

for {
    desired := getDesiredState()
    actual := getActualState()
    if desired != actual {
        reconcile(desired, actual)
    }
}

7.2 内蔵 Controller

Deployment、ReplicaSet、StatefulSet、DaemonSet、Job、Node、Service、Endpoint、Namespace、PersistentVolume。

7.3 性質

  • 冪等 (idempotent)、自己修復、監査可能。
  • 代償: eventual consistency。

7.4 Operator

CRD + Controller。Kubernetes の拡張性の中核。PostgreSQL、Kafka、Cassandra などがそれぞれ Operator を持つ。

★ Insight ─────────────────────────────────────

  • Reconciliation は Borg 由来: RPC ベースの命令的システムは部分障害に弱い。宣言的 + 永続収束で自動復旧になる。
  • Operator が Kubernetes を汎用分散プラットフォームにした
  • Eventual consistency は意図的な選択: strong consistency は遅く複雑になる。 ─────────────────────────────────────────────────

8. kubelet — ノードエージェント

8.1 役割

自ノード宛 Pod の watch、CRI でのコンテナ制御、CNI 設定、CSI マウント、probe 実行、状態報告。

8.2 Pod ライフサイクル

Pending -> ContainerCreating -> Running -> Succeeded/Failed -> Unknown。

8.3 Probe

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

Liveness (失敗で再起動)、Readiness (失敗で Service から除外)、Startup (初期化中)。

8.4 Resource Limits

resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"

requests は Scheduler が、limits は kubelet が cgroup で強制。

8.5 Eviction

ノード逼迫時の追い出し順: BestEffort -> Burstable -> Guaranteed。Guaranteed Pod が最も安定。

8.6 Static Pod

/etc/kubernetes/manifests/ の YAML を kubelet が直接管理。control plane のブートストラップに使う。


9. kube-proxy — Service の実装

9.1 Service とは

Pod グループへの安定 endpoint。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 8080

9.2 モード

  • iptables (デフォルト): DNAT 規則で実装。大規模では規則数が爆発。
  • IPVS: カーネル L4 LB。rr/least-conn 対応。
  • eBPF (Cilium): kube-proxy を置き換え、BPF map で実装。

iptables の例:

-A KUBE-SERVICES -d 10.96.123.456/32 -p tcp --dport 80 -j KUBE-SVC-XXX
-A KUBE-SVC-XXX -m statistic --mode random --probability 0.5 -j KUBE-SEP-AAA
-A KUBE-SEP-AAA -p tcp -j DNAT --to-destination 10.0.1.10:8080

9.3 Service 種別

ClusterIP、NodePort、LoadBalancer、ExternalName。

9.4 EndpointSlice

旧 Endpoints を分割し、watch 効率を上げる。


10. CRI, CNI, CSI — プラグインインターフェース

10.1 CRI

kubelet とコンテナランタイム間の gRPC。

service RuntimeService {
    rpc CreatePodSandbox(CreatePodSandboxRequest) returns (CreatePodSandboxResponse);
    rpc StartContainer(StartContainerRequest) returns (StartContainerResponse);
}

実装: containerd、CRI-O (Docker shim は 1.24 で削除)。

10.2 CNI

ADD <network> <container>
DEL <network> <container>
CHECK <network> <container>

/etc/cni/net.d/ にプラグインバイナリ。主要: bridge, calico, flannel, cilium, weave。

10.3 CSI

gRPC のストレージプラグイン。Identity / Controller (CreateVolume, attach) / Node (mount) 3 サービス構成。ドライバ: AWS EBS、GCE PD、Azure Disk、Ceph、Longhorn。

10.4 モデルの美しさ

標準 API + 差し替え可能な実装。ベンダーロックインなし。


11. 主要オブジェクト

  • Pod: 最小単位。コンテナ間で namespace を共有。
  • ReplicaSet: N 個の Pod を保証。
  • Deployment: ReplicaSet + rolling update + rollback。
  • StatefulSet: 順序付き Pod、安定 hostname、PV。
  • DaemonSet: 各ノードに 1 Pod。
  • Job / CronJob: バッチと定期バッチ。
  • ConfigMap / Secret: 設定と機密 (base64、任意で at-rest 暗号化)。

Deployment 例:

apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

12. ネットワーキング

12.1 Kubernetes ネットワークモデル

各 Pod が固有 IP を持ち、Pod 同士・Pod とノードは NAT なしで通信、Pod は自身の IP で相互認識する。

12.2 サービスディスカバリ

CoreDNS が my-service.my-namespace.svc.cluster.local を ClusterIP に解決。Headless Service (clusterIP: None) は Pod IP を直接返す。

12.3 Ingress / Gateway API

Ingress は L7 入口。Gateway API は次世代 (2023 年 stable)。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
spec:
  parentRefs:
  - name: my-gateway
  hostnames: ["api.example.com"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: api-service
      port: 80

12.4 NetworkPolicy

適用されると該当 Pod は default-deny になる。CNI 側実装が必要 (Calico、Cilium がよく対応)。


13. ストレージ

  • PV: クラスタのストレージ資源。
  • PVC: ユーザー要求。
  • StorageClass: 動的プロビジョナ。

Access mode: ReadWriteOnce、ReadOnlyMany、ReadWriteMany。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  storageClassName: gp3
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi

StatefulSet は volumeClaimTemplates で Pod ごとに PV を作る。


14. セキュリティ

14.1 RBAC

Role/ClusterRole と RoleBinding/ClusterRoleBinding。

14.2 ServiceAccount

ワークロードの identity。トークンは /var/run/secrets/kubernetes.io/serviceaccount/token にマウント。

14.3 Pod Security Standards

privileged、baseline、restricted の 3 段階。namespace ラベルで強制:

metadata:
  labels:
    pod-security.kubernetes.io/enforce: restricted

PSP は 1.25 で削除、PSS が標準。

14.4 Secret 管理

Kubernetes Secret は base64 であり暗号化ではない。etcd encryption-at-rest、Vault、AWS Secrets Manager、Sealed Secrets などを併用する。


15. 限界と課題

複雑さ (学習コスト)、大規模クラスタでの etcd 負荷、ネットワーク層の複雑化、control plane のコスト、namespace はソフトな隔離にすぎないマルチテナンシーの弱さ。


16. 代替

  • Nomad: より単純、軽量、非コンテナも扱える。
  • Docker Swarm: ほぼ deprecated。
  • Mesos: 歴史上の存在。
  • ECS: AWS ロックイン。
  • Cloud Run / Lambda: サーバレス。
  • k3s: エッジ。

標準性・規模・マルチクラウドが必要なら Kubernetes。


17. 未来

Sidecar-less Service Mesh (Cilium)、Gateway API、WebAssembly ワークロード (krustlet、wasmCloud)、Confidential Computing (SGX、SEV)、KubeVirt、sched_ext によるワークロード別スケジューリング。


18. 結論

Kubernetes は単なるツールではない。Borg から 10 年で蒸留された分散インフラのデファクトスタンダードであり、すべての主要クラウドがマネージドで提供し、新しいインフラは基本これを前提とする。深く理解することはもはやモダンインフラエンジニアの必須教養である。

本稿で Linux インフラシリーズ (ブート、スケジューラ、io_uring、メモリ、eBPF、コンテナ、そしてオーケストレーション) が完結する。モダンな cloud-native スタックの上で自分のコードがどう生きるかの全景が見えたはずだ。


付録 — FAQ

小さなアプリに Kubernetes は必要? たいていは不要。Docker Compose、systemd、PaaS の方が単純。

self-hosted と managed、どちら? 小チームなら managed (EKS/GKE/AKS)。専任インフラチームがあるなら self-hosted も可。

etcd 運用は本当に危険? そう。バックアップ・監視・defrag・アップグレードを慎重に。managed が自動化してくれる。

DB を Kubernetes で動かす? 成熟した Operator があるので可能。ただし managed RDS の魅力も大きい。

kubectl 以外のツール? helm、kustomize、k9s、stern、kubectx/kubens、lens。