LESSON 40分

「Kubernetes を本番で運用するなら、内部アーキテクチャを深く理解する必要がある。コントロールプレーンの各コンポーネントが何をしているか、障害時にどう振る舞うか。それを知らずに本番運用は語れない」と佐藤CTOが厳しく言った。

推定読了時間: 40分


コントロールプレーンの全体像

graph TB
    subgraph CP["Control Plane"]
        API["kube-apiserver<br/>RESTful API エンドポイント"]
        SCHED["kube-scheduler<br/>Pod 配置決定"]
        CM["kube-controller-manager<br/>状態管理ループ"]
        ETCD[("etcd<br/>分散KVS")]
    end

    subgraph WN["Worker Node"]
        KUBELET["kubelet<br/>Pod ライフサイクル管理"]
        PROXY["kube-proxy<br/>Service ネットワーク"]
        CRI["Container Runtime<br/>CRI 準拠"]
        subgraph PODS["Pods"]
            PA(["Pod A"])
            PB(["Pod B"])
            PC(["Pod C"])
        end
    end

    API -->|read/write| ETCD
    SCHED -->|via API| ETCD
    CM -->|via API| ETCD
    SCHED --- API
    CM --- API
    API -->|watch/指示| KUBELET
    KUBELET --> CRI
    KUBELET --> PROXY
    CRI --> PA
    CRI --> PB
    CRI --> PC

    classDef cpNode fill:#3b82f6,stroke:#1d4ed8,color:#fff
    classDef etcdNode fill:#8b5cf6,stroke:#6d28d9,color:#fff
    classDef wnNode fill:#10b981,stroke:#047857,color:#fff
    classDef podNode fill:#f59e0b,stroke:#d97706,color:#fff
    classDef cpBox fill:#eff6ff,stroke:#3b82f6,color:#1e3a5f
    classDef wnBox fill:#ecfdf5,stroke:#10b981,color:#064e3b
    classDef podBox fill:#fffbeb,stroke:#f59e0b,color:#78350f

    class API,SCHED,CM cpNode
    class ETCD etcdNode
    class KUBELET,PROXY,CRI wnNode
    class PA,PB,PC podNode
    class CP cpBox
    class WN wnBox
    class PODS podBox

kube-apiserver

Kubernetes の全てのコンポーネントの中心。RESTful API を提供し、etcd への唯一のアクセスポイントです。

機能説明
認証 (Authentication)誰がリクエストしているか
認可 (Authorization)何が許可されているか (RBAC)
Admission Controlリクエストの検証と変更
API AggregationカスタムAPIの統合
graph LR
    REQ["Client Request<br/>kubectl / API call"]
    AUTHN{{"Authentication<br/>x509, OIDC, Token"}}
    AUTHZ{{"Authorization<br/>RBAC"}}
    ADM{{"Admission<br/>Webhook"}}
    ETCD[("etcd<br/>永続化")]

    REQ --> AUTHN --> AUTHZ --> ADM --> ETCD

    classDef reqNode fill:#6366f1,stroke:#4338ca,color:#fff
    classDef authNode fill:#f97316,stroke:#c2410c,color:#fff
    classDef admNode fill:#ec4899,stroke:#be185d,color:#fff
    classDef etcdNode fill:#8b5cf6,stroke:#6d28d9,color:#fff

    class REQ reqNode
    class AUTHN,AUTHZ authNode
    class ADM admNode
    class ETCD etcdNode

Admission Controller の流れ

# MutatingWebhookConfiguration の例
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: inject-sidecar
webhooks:
  - name: sidecar-injector.example.com
    clientConfig:
      service:
        name: sidecar-injector
        namespace: system
        path: "/inject"
    rules:
      - operations: ["CREATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    namespaceSelector:
      matchLabels:
        sidecar-injection: enabled

etcd

分散キーバリューストア。クラスタの全ての状態を永続化します。

graph TB
    subgraph CLUSTER["etcd クラスタ"]
        N1[("Node 1<br/>Leader")]
        N2[("Node 2<br/>Follower")]
        N3[("Node 3<br/>Follower")]
        RAFT["Raft Consensus<br/>合意プロトコル"]
    end

    N1 <-->|replicate| N2
    N1 <-->|replicate| N3
    N2 <-->|heartbeat| N3
    N1 --- RAFT
    N2 --- RAFT
    N3 --- RAFT

    classDef leaderNode fill:#f59e0b,stroke:#d97706,color:#fff
    classDef followerNode fill:#8b5cf6,stroke:#6d28d9,color:#fff
    classDef raftNode fill:#374151,stroke:#111827,color:#fff
    classDef clusterBox fill:#faf5ff,stroke:#8b5cf6,color:#3b0764

    class N1 leaderNode
    class N2,N3 followerNode
    class RAFT raftNode
    class CLUSTER clusterBox

etcd の運用上の注意点

項目推奨
ノード数3 or 5(奇数)
ディスクSSD 必須(IOPS重視)
バックアップ定期的なスナップショット
監視etcd_disk_wal_fsync_duration_seconds
# etcd バックアップ
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt \
  --key=/etc/kubernetes/pki/etcd/healthcheck-client.key

kube-scheduler

Pod をどのノードに配置するかを決定します。

スケジューリングの流れ

graph LR
    PENDING(["Pending Pod"])
    FILTER["1. Filtering<br/>フィルタリング<br/>条件を満たさない<br/>ノードを除外"]
    SCORE["2. Scoring<br/>スコアリング<br/>残りのノードに<br/>スコアを付与"]
    BIND["3. Binding<br/>バインディング<br/>最高スコアの<br/>ノードに割り当て"]
    SCHEDULED(["Scheduled Pod"])

    PENDING --> FILTER --> SCORE --> BIND --> SCHEDULED

    FILTER -.-|"リソース不足<br/>nodeSelector不一致<br/>Taint"| EX1[" "]
    SCORE -.-|"リソースの空き<br/>Pod の分散度"| EX2[" "]

    classDef podNode fill:#f59e0b,stroke:#d97706,color:#fff
    classDef stepNode fill:#3b82f6,stroke:#1d4ed8,color:#fff
    classDef hidden fill:none,stroke:none,color:#64748b,font-size:10px

    class PENDING,SCHEDULED podNode
    class FILTER,SCORE,BIND stepNode
    class EX1,EX2 hidden
# Pod のスケジューリング制約
apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  # Node Affinity
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: node.kubernetes.io/instance-type
                operator: In
                values: ["m6g.xlarge", "m6g.2xlarge"]
    # Pod Anti-Affinity(同じノードに同じPodを置かない)
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 100
          podAffinityTerm:
            labelSelector:
              matchExpressions:
                - key: app
                  operator: In
                  values: ["api-server"]
            topologyKey: kubernetes.io/hostname
  # Topology Spread Constraints
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: topology.kubernetes.io/zone
      whenUnsatisfiable: DoNotSchedule
      labelSelector:
        matchLabels:
          app: api-server

kubelet

各ワーカーノードで動作し、Pod のライフサイクルを管理します。

graph TB
    APISVR["kube-apiserver"]
    KUBELET["kubelet<br/>Pod ライフサイクル管理"]

    subgraph CRI_GRP["CRI - Container Runtime Interface"]
        CRI_IF{{"CRI"}}
        CONTAINERD(["containerd"])
        CRIO(["CRI-O"])
    end

    subgraph CNI_GRP["CNI - Container Network Interface"]
        CNI_IF{{"CNI"}}
        CALICO(["Calico"])
        CILIUM(["Cilium"])
        VPCCNI(["AWS VPC CNI"])
    end

    subgraph CSI_GRP["CSI - Container Storage Interface"]
        CSI_IF{{"CSI"}}
        EBS(["EBS CSI"])
        EFS(["EFS CSI"])
        CEPH(["Ceph"])
    end

    APISVR -->|watch| KUBELET
    KUBELET --> CRI_IF
    KUBELET --> CNI_IF
    KUBELET --> CSI_IF
    CRI_IF --> CONTAINERD
    CRI_IF --> CRIO
    CNI_IF --> CALICO
    CNI_IF --> CILIUM
    CNI_IF --> VPCCNI
    CSI_IF --> EBS
    CSI_IF --> EFS
    CSI_IF --> CEPH

    classDef apiNode fill:#3b82f6,stroke:#1d4ed8,color:#fff
    classDef kubeletNode fill:#10b981,stroke:#047857,color:#fff
    classDef ifNode fill:#f97316,stroke:#c2410c,color:#fff
    classDef implNode fill:#64748b,stroke:#334155,color:#fff
    classDef criBox fill:#fef3c7,stroke:#f59e0b,color:#78350f
    classDef cniBox fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
    classDef csiBox fill:#fce7f3,stroke:#ec4899,color:#831843

    class APISVR apiNode
    class KUBELET kubeletNode
    class CRI_IF,CNI_IF,CSI_IF ifNode
    class CONTAINERD,CRIO,CALICO,CILIUM,VPCCNI,EBS,EFS,CEPH implNode
    class CRI_GRP criBox
    class CNI_GRP cniBox
    class CSI_GRP csiBox

CRI / CNI / CSI

インターフェース役割主な実装
CRIコンテナランタイムcontainerd, CRI-O
CNIネットワークCalico, Cilium, AWS VPC CNI
CSIストレージEBS CSI, EFS CSI, Ceph CSI
# StorageClass (CSI)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iops: "5000"
  throughput: "250"
  encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

kube-proxy

各ノードでネットワークルールを管理し、Service の負荷分散を実現します。

モード比較

モード仕組みパフォーマンス
iptablesiptables ルール中(ルール数に比例して劣化)
IPVSカーネル内ロードバランサー高(大規模向け)
eBPF (Cilium)カーネル内プログラマブル最高
# kube-proxy の設定(IPVS モード)
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
  scheduler: rr  # round-robin
  syncPeriod: 30s
eBPF と Cilium の詳細

Cilium は kube-proxy を完全に置き換え、eBPF をベースにしたネットワーキングを提供します。

# Cilium のインストール(Helm)
# helm install cilium cilium/cilium --namespace kube-system \
#   --set kubeProxyReplacement=true \
#   --set k8sServiceHost=${API_SERVER_IP} \
#   --set k8sServicePort=6443

# CiliumNetworkPolicy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: api-server-policy
spec:
  endpointSelector:
    matchLabels:
      app: api-server
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: api-gateway
      toPorts:
        - ports:
            - port: "3000"
              protocol: TCP

メリット:

  • kube-proxy より高パフォーマンス
  • L7レベルのポリシー適用
  • 透過的な暗号化(WireGuard)
  • Hubble による可観測性

コントロールプレーンの高可用性

graph LR
    LB(["Load Balancer"])

    subgraph APIS["kube-apiserver x3"]
        API1["kube-apiserver-1"]
        API2["kube-apiserver-2"]
        API3["kube-apiserver-3"]
    end

    subgraph ETCD_HA["etcd cluster (3 nodes)"]
        E1[("etcd-1")]
        E2[("etcd-2")]
        E3[("etcd-3")]
    end

    NOTE["※ scheduler / controller-manager<br/>リーダー選出により1台のみアクティブ"]

    LB --> API1
    LB --> API2
    LB --> API3
    API1 --> E1
    API2 --> E2
    API3 --> E3
    E1 <--> E2
    E2 <--> E3
    E1 <--> E3

    classDef lbNode fill:#f97316,stroke:#c2410c,color:#fff
    classDef apiNode fill:#3b82f6,stroke:#1d4ed8,color:#fff
    classDef etcdNode fill:#8b5cf6,stroke:#6d28d9,color:#fff
    classDef noteNode fill:#fef9c3,stroke:#ca8a04,color:#713f12
    classDef apiBox fill:#eff6ff,stroke:#3b82f6,color:#1e3a5f
    classDef etcdBox fill:#faf5ff,stroke:#8b5cf6,color:#3b0764

    class LB lbNode
    class API1,API2,API3 apiNode
    class E1,E2,E3 etcdNode
    class NOTE noteNode
    class APIS apiBox
    class ETCD_HA etcdBox
# EKS のコントロールプレーン(マネージド)
# Terraform での EKS クラスタ定義
resource "aws_eks_cluster" "main" {
  name     = "production"
  role_arn = aws_iam_role.cluster.arn
  version  = "1.29"

  vpc_config {
    subnet_ids              = var.private_subnets
    endpoint_private_access = true
    endpoint_public_access  = false
    security_group_ids      = [aws_security_group.cluster.id]
  }

  # コントロールプレーンのログ
  enabled_cluster_log_types = [
    "api", "audit", "authenticator",
    "controllerManager", "scheduler"
  ]
}

まとめ

コンポーネント役割障害時の影響
kube-apiserverAPI エンドポイント全操作が不可能
etcd状態の永続化データ損失の危険
kube-schedulerPod の配置決定新規Podがスケジュールされない
kube-controller-manager望ましい状態の維持自動修復が停止
kubeletPod のライフサイクル管理ノード上のPodが管理不能
kube-proxyService のネットワークService 経由の通信が不通

チェックリスト

  • コントロールプレーンの各コンポーネントの役割を理解している
  • etcd の重要性とバックアップ戦略を理解している
  • CRI/CNI/CSI のインターフェース層を理解している
  • kube-proxy のモード(iptables/IPVS/eBPF)の違いを理解している
  • Admission Controller の仕組みを理解している
  • コントロールプレーンの高可用性構成を理解している

次のステップへ

次のレッスンでは、Kubernetes のワークロードパターン(Deployment、StatefulSet、DaemonSet 等)を深掘りします。