1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetesってなんだ?〜docker compose upの「その先」にあるコンテナオーケストレーションの世界〜

1
Posted at

この記事の対象読者

  • DockerDocker Composeの基本は理解している方
  • 「コンテナが1台のマシンに収まらなくなったらどうするんだ?」と疑問を持ち始めた方
  • AI/ML基盤やマイクロサービスの本番運用に向けて、コンテナオーケストレーションの全体像を掴みたい方

この記事で得られること

  • Kubernetesの本質: 「なぜDocker Composeでは不十分なのか」が腹落ちする
  • コアコンセプトの完全理解: Pod、Deployment、Service、Namespace — 全てが「宣言的管理」で繋がる
  • 実践力: minikubeでのローカル構築から、GPUワークロードのスケジューリングまで体験できる

この記事で扱わないこと

  • Kubernetesクラスタの本番構築(kubeadm、EKS、GKE等の詳細)
  • Helm、Kustomize等のパッケージ管理ツールの詳細
  • Istio等のサービスメッシュ

1. Kubernetesとの出会い

docker compose upで全てが動いた時、私は満足していた。8台のコンテナが1台のマシンで快適に動く。しかしその「1台」が死んだら?

事の発端は、RTX 5090環境でOllama + Open WebUI + PostgreSQL + Redisの構成をDocker Composeで組んだ時のことです。ローカルでは完璧に動いている。しかし次の3つの疑問が浮かんできました。

  1. このマシンが落ちたら、全サービスが停止する(単一障害点)
  2. リクエストが増えたら、コンテナを別のマシンに分散したい(スケールアウト)
  3. コンテナが異常終了したら、自動で復旧してほしい(セルフヒーリング)

Docker Composeは「1台のマシン内で複数コンテナを管理する」ツールです。では、複数のマシンにまたがるコンテナ群を管理するにはどうすればいいのか。

Kubernetes(K8s)は、複数マシンをひとつのクラスタとして束ね、コンテナの配置・スケーリング・自己回復を自動で行うオーケストレーションプラットフォームです。

料理に例えるなら、Dockerは「一皿を作る技術」、Docker Composeは「コース料理のレシピ」、そしてKubernetesは「厨房全体のオペレーションシステム」です。シェフ(Node)が何人いても、注文(ワークロード)を最適に振り分け、誰かが倒れたら別の人が代わりに料理を仕上げる。

ここまでで、Kubernetesの存在意義がなんとなくイメージできたでしょうか。次は、この記事で使う用語を整理しておきましょう。


2. 前提知識の確認

本題に入る前に、この記事で頻出する用語を確認します。

2.1 クラスタ(Cluster)とは

Kubernetesにおけるクラスタは、1台以上のマシン(ノード)をまとめた「コンテナを動かすための基盤」です。1台のマシンでも、100台のマシンでも、Kubernetesの視点からは「1つのクラスタ」として統一的に扱えます。

2.2 ノード(Node)とは

クラスタを構成する個々のマシンです。コントロールプレーンノード(司令塔)とワーカーノード(実際にコンテナを動かす現場)の2種類があります。物理マシンでも仮想マシンでもOKです。

2.3 マニフェスト(Manifest)とは

Kubernetesに「こういう状態にしてくれ」と伝えるYAMLファイルです。Docker Composecompose.yamlに相当しますが、Kubernetesのマニフェストは「リソースの種類(Kind)」ごとに分かれているのが特徴です。

2.4 宣言的管理(Declarative Management)とは

「3つのWebサーバーが動いている状態にしてくれ」と目標状態を宣言すると、Kubernetesが現在の状態とのギャップを自動的に埋めてくれる管理モデルです。「コンテナを起動しろ」「停止しろ」と命令する命令的(Imperative)管理とは根本的に異なります。1台落ちたら自動で1台追加してくれるセルフヒーリングの土台もこの仕組みです。

2.5 kubectl(キューブシーティーエル)とは

Kubernetesクラスタを操作するためのCLIツールです。Dockerdockerコマンド、Docker Composedocker composeコマンドに相当します。

これらの用語が押さえられたら、Kubernetesの歴史と背景を見ていきましょう。


3. Kubernetesが生まれた背景

3.1 Google社内の「秘密兵器」 — Borg

Kubernetesの物語は、2000年代初頭のGoogleから始まります。

当時のGoogleは、検索エンジン、Gmail、YouTube等のサービスを数十万台のサーバーで運用していました。この規模になると「人間が手動でサーバーを管理する」のは不可能です。そこで開発されたのが、社内コンテナ管理システムBorgでした。

BorgはStar Trekに登場する「集合意識体」が名前の由来。個体が自律的に動きながら全体として1つのシステムとして機能する — まさにクラスタ管理の比喩です。

Borgは10年以上にわたってGoogleの基盤を支え続けましたが、社外には公開されませんでした。Googleにとって「競争優位」だったからです。

3.2 Docker登場とオーケストレーション戦争

2013年、Dockerがコンテナ技術を一般開発者にとって手軽なものに変えました。しかし「コンテナをどう大規模に管理するか」は未解決のまま。そこでGoogleのBorgチームの数名が、Borgの設計思想をオープンソースで再構築するプロジェクトを始めます。

社内コードネームは「Project Seven of Nine」。こちらもStar Trekネタで、Borgから解放されたキャラクターの名前です。Kubernetesのロゴにある7本のスポークは、このコードネームに由来します。

2014年6月 — GoogleがKubernetesをオープンソースとして公開。

その後、コンテナオーケストレーションの覇権を巡って「三国志」が勃発します。

出来事
2014年6月 Google、Kubernetesをオープンソース公開
2015年7月 Kubernetes v1.0リリース。同時にCNCF(Cloud Native Computing Foundation)設立、初のホストプロジェクトに
2015年秋 Docker Swarm登場 — Docker社の公式オーケストレーター
2016-2017年 Kubernetes vs Docker Swarm vs Apache Mesos の「オーケストレーション戦争」
2017年末 AWS、Azure、GCPの全主要クラウドがKubernetesをマネージドサービスとして提供開始
2018年 Docker社がKubernetesをDocker Desktopに統合 — 事実上の降伏宣言
2024年 CNCF年次調査: 92%の組織がコンテナを本番運用、K8sがデファクトスタンダードに

Docker SwarmとKubernetesは「競合」と説明されることが多いですが、レイヤーが異なります。Dockerはコンテナランタイム、Kubernetesはオーケストレーター。現在もKubernetesの内部でDockerのコンテナ技術(containerd)は使われています。

3.3 2026年のKubernetes — v1.35 "Timbernetes"

2026年3月現在の最新安定版はKubernetes v1.35.1(2026年2月10日リリース)。コードネームは "Timbernetes(The World Tree Release)" です。60の新機能強化が含まれ、特にAI/ML向けの進化が目立ちます。

機能 ステータス 概要
In-Place Pod Resource Resize GA(安定版) Podを再起動せずにCPU/メモリを変更可能
Gang Scheduling Alpha 分散学習ジョブの「全Pod同時起動 or 起動しない」制御
Dynamic Resource Allocation(DRA) GA(v1.34〜) GPU等の特殊ハードウェアを柔軟に割り当て
RestartAllContainers Alpha AI/MLジョブの障害回復をPod内で完結
maxParallelImagePulls GA イメージ並列ダウンロード数を制御、大規模クラスタの起動高速化
Pod証明書(mTLS) Beta Pod単位でx.509証明書を自動発行・ローテーション

v1.35の目玉はIn-Place Pod Resource Resize(GA) です。従来、Podのリソース変更にはPodの再作成が必要でした。AI推論サービスのような「再起動のコストが高い」ワークロードにとって、これは革命的な変化です。

また、次期バージョン v1.36 は2026年4月22日リリース予定で、Gateway APIの大幅強化とWindowsコンテナサポートの改善が予告されています。

背景がわかったところで、基本的な仕組みを見ていきましょう。


4. 基本概念と仕組み

4.1 Kubernetesのアーキテクチャ全体像

Kubernetesクラスタは、大きくコントロールプレーン(司令塔)とワーカーノード(現場)に分かれます。

┌──────────────────────── Kubernetes Cluster ────────────────────────────┐
│                                                                        │
│  ┌─── Control Plane(コントロールプレーン)───────────────────────┐     │
│  │                                                                │     │
│  │  ┌──────────┐  ┌───────────┐  ┌──────────┐  ┌─────────────┐  │     │
│  │  │ API      │  │ etcd      │  │Scheduler │  │ Controller  │  │     │
│  │  │ Server   │  │(状態保存) │  │(配置決定)│  │ Manager     │  │     │
│  │  └──────────┘  └───────────┘  └──────────┘  └─────────────┘  │     │
│  └────────────────────────────────────────────────────────────────┘     │
│                           │ kubectl / API                              │
│  ┌─── Worker Node 1 ─────┼───────────┐  ┌─── Worker Node 2 ──────┐   │
│  │  ┌────────┐            │           │  │  ┌────────┐            │   │
│  │  │kubelet │  ┌─────────────────┐   │  │  │kubelet │  ┌──────┐ │   │
│  │  └────────┘  │   Pod A         │   │  │  └────────┘  │Pod C │ │   │
│  │  ┌────────┐  │ ┌────┐ ┌────┐  │   │  │  ┌────────┐  └──────┘ │   │
│  │  │kube-   │  │ │ C1 │ │ C2 │  │   │  │  │kube-   │  ┌──────┐ │   │
│  │  │proxy   │  │ └────┘ └────┘  │   │  │  │proxy   │  │Pod D │ │   │
│  │  └────────┘  └─────────────────┘   │  │  └────────┘  └──────┘ │   │
│  │              ┌──────┐              │  │                        │   │
│  │              │Pod B │              │  │                        │   │
│  │              └──────┘              │  │                        │   │
│  └────────────────────────────────────┘  └────────────────────────┘   │
└────────────────────────────────────────────────────────────────────────┘

コントロールプレーンの主要コンポーネント:

コンポーネント 役割 料理の例え
API Server 全ての操作の入り口。kubectlもここを通る レストランのフロント受付
etcd クラスタの状態を保存する分散KVS 全注文を記録する台帳
Scheduler Podをどのノードに配置するか決定 席の案内係
Controller Manager 「宣言された状態」と「実際の状態」のギャップを埋め続ける 店長(問題を自動修復)

ワーカーノードの主要コンポーネント:

コンポーネント 役割
kubelet ノード上のコンテナ管理エージェント。Podの起動・監視・報告を行う
kube-proxy ネットワークルーティング。Serviceへのトラフィックを適切なPodに転送
Container Runtime 実際にコンテナを動かすエンジン(containerd、CRI-O等)

4.2 Pod — Kubernetesの最小単位

Pod(ポッド)は、Kubernetesでコンテナを動かす最小デプロイ単位です。

Dockerの世界では「コンテナ」が最小単位ですが、Kubernetesでは「Pod」です。Pod内には1つ以上のコンテナが含まれ、同じネットワーク空間(IPアドレス)とストレージを共有します。

┌─────── Pod ─────────────────────────────────────────┐
│                                                      │
│  ┌────────────────┐  ┌────────────────────────────┐  │
│  │ メインコンテナ │  │ サイドカーコンテナ         │  │
│  │ (Webサーバー)  │  │ (ログ収集 / プロキシ)     │  │
│  └────────────────┘  └────────────────────────────┘  │
│                                                      │
│  共有: IPアドレス / localhost通信 / ボリューム       │
└──────────────────────────────────────────────────────┘

「1 Pod = 1 コンテナ」が基本パターンです。複数コンテナを入れるのは「メイン + サイドカー」構成(ログ収集、プロキシ等)のような明確な理由がある場合に限ります。

Docker Composeとの比較:

概念 Docker Compose Kubernetes
コンテナの単位 サービス(service) Pod
複数コンテナのグルーピング compose.yaml全体 Pod内のコンテナ群
IPアドレス コンテナごとに異なる Pod内は同一IP
スケーリング docker compose up --scale web=3 Deploymentのreplicas: 3

4.3 Deployment — 「望ましい状態」を宣言する

Deploymentは、「このPodを何個動かし続けてほしいか」を宣言するリソースです。

Podを直接作ることもできますが、実運用ではDeploymentを使います。なぜなら、Deploymentは以下を自動で行ってくれるからです。

  • レプリカ管理: 指定した数のPodを常に維持
  • セルフヒーリング: Podが落ちたら自動で新しいPodを作成
  • ローリングアップデート: アプリの更新時にダウンタイムなしでPodを入れ替え
  • ロールバック: 更新に失敗したら前のバージョンに戻す
# deployment.yaml — 最もシンプルな例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3            # 常に3つのPodを維持
  selector:
    matchLabels:
      app: web-app
  template:              # Podのテンプレート
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: nginx:1.27
        ports:
        - containerPort: 80
        resources:
          requests:       # 最低限必要なリソース
            cpu: "100m"
            memory: "128Mi"
          limits:         # 上限
            cpu: "500m"
            memory: "256Mi"

この1枚のマニフェストを適用するだけで、Kubernetesは3つのPodを起動し、1つが落ちたら自動で復旧し、リソース使用量を監視してくれます。

4.4 Service — Podへの安定したアクセス経路

Podは短命です。落ちたら新しいPodが別のIPアドレスで生まれます。では、他のサービスやユーザーは「どのIP」にアクセスすればいいのか?

Service(サービス)は、Podの集合に対して安定したDNS名とIPアドレスを提供するリソースです。

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-app-service
spec:
  selector:
    app: web-app          # label「app: web-app」を持つPodにトラフィックを転送
  ports:
  - port: 80              # Service自体のポート
    targetPort: 80        # Pod内コンテナのポート
  type: ClusterIP         # クラスタ内部のみアクセス可能(デフォルト)

Serviceのタイプ:

タイプ アクセス範囲 用途
ClusterIP クラスタ内部のみ マイクロサービス間通信
NodePort クラスタ外部(ノードのIP:ポート) 開発・テスト用
LoadBalancer クラウドのロードバランサー経由 本番Web公開

Docker Composeでは、サービス名がそのままDNS名になりました(例: http://postgres:5432)。KubernetesのServiceも同じ思想ですが、「Podの集合」に対してDNS名を付ける点が異なります。http://web-app-service:80でアクセスすると、背後の3つのPodに自動で負荷分散されます。

4.5 Namespace — クラスタ内の仮想的な仕切り

Namespaceは、1つのクラスタ内にリソースの論理的な境界を作る仕組みです。

┌────────── Kubernetes Cluster ──────────────────────┐
│                                                     │
│  ┌── Namespace: dev ──┐  ┌── Namespace: prod ──┐   │
│  │  web-app (3 Pod)   │  │  web-app (10 Pod)   │   │
│  │  db (1 Pod)        │  │  db-primary (1 Pod) │   │
│  │  redis (1 Pod)     │  │  db-replica (2 Pod) │   │
│  └────────────────────┘  │  redis (3 Pod)      │   │
│                          └──────────────────────┘   │
│  ┌── Namespace: monitoring ─────────────────────┐   │
│  │  prometheus (1 Pod)  │  grafana (1 Pod)      │   │
│  └──────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

同じweb-appという名前のDeploymentでも、devprodで完全に独立して管理できます。チームやプロジェクトごとにNamespaceを分けるのが一般的です。

4.6 ConfigMap / Secret — 設定と機密情報の分離

リソース 用途 保存形式
ConfigMap 非機密の設定情報(DB接続先、機能フラグ等) 平文
Secret 機密情報(パスワード、APIキー、TLS証明書等) Base64エンコード
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DATABASE_HOST: "postgres-service"
  LOG_LEVEL: "INFO"

---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  DATABASE_PASSWORD: c2VjcmV0MTIz    # echo -n 'secret123' | base64

KubernetesのSecretはデフォルトではBase64エンコードのみです。暗号化ではありません。本番運用ではetcdの暗号化やExternal Secret Operator等の導入を検討してください。

基本概念が理解できたところで、実際にコードを書いて動かしてみましょう。


5. 実践:実際に使ってみよう

5.1 環境構築 — minikubeでローカルKubernetesクラスタを起動

本番ではAWS EKSやGoogle GKE等のマネージドサービスを使いますが、学習にはminikubeが最適です。ローカルPCに1ノードのKubernetesクラスタを構築できます。

ローカルKubernetesツールの比較:

ツール 特徴 向いている用途
minikube 最もポピュラー。アドオン豊富 学習、機能検証
kind Dockerコンテナ内にクラスタ構築。起動が速い CI/CDパイプライン
k3s 軽量K8sディストリビューション。バイナリ100MB未満 エッジ、IoT、リソース制約環境
# --- minikube + kubectl のインストール ---

# macOS (Homebrew)
brew install minikube kubectl

# Windows (WSL2環境推奨 — WSLの導入は下記記事参照)
# https://qiita.com/GeneLab_999/items/29ee4567b0254d47bbc8
choco install minikube kubernetes-cli

# Linux (Ubuntu — Ubuntuの導入は下記記事参照)
# https://qiita.com/GeneLab_999/items/be33633ff1b27f813214
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# --- クラスタの起動 ---
minikube start --driver=docker --cpus=2 --memory=4096

# 確認
kubectl cluster-info
kubectl get nodes

WSL環境でminikubeを使う場合は--driver=dockerが推奨です。WSL2のDockerが有効になっていることを確認してください。

5.2 環境別の設定ファイル

KubernetesでもDocker Compose同様、環境ごとに設定を分けます。Namespaceで環境を分離し、ConfigMapで設定値を切り替えるのが基本パターンです。

開発環境用(configmap-dev.yaml)

# configmap-dev.yaml — 開発環境用(このままコピーして使える)
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: dev
data:
  ENVIRONMENT: "development"
  DEBUG: "true"
  LOG_LEVEL: "DEBUG"
  DATABASE_HOST: "postgres-service"
  DATABASE_PORT: "5432"
  REDIS_HOST: "redis-service"
  OLLAMA_HOST: "http://ollama-service:11434"

本番環境用(configmap-prod.yaml)

# configmap-prod.yaml — 本番環境用
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: prod
data:
  ENVIRONMENT: "production"
  DEBUG: "false"
  LOG_LEVEL: "INFO"
  DATABASE_HOST: "postgres-primary-service"
  DATABASE_PORT: "5432"
  REDIS_HOST: "redis-cluster-service"
  OLLAMA_HOST: "http://ollama-service:11434"

テスト環境用(configmap-test.yaml)

# configmap-test.yaml — CI/CD用
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: test
data:
  ENVIRONMENT: "test"
  DEBUG: "true"
  LOG_LEVEL: "DEBUG"
  DATABASE_HOST: "postgres-test-service"
  DATABASE_PORT: "5432"
  REDIS_HOST: "redis-test-service"
  OLLAMA_HOST: "http://ollama-test-service:11434"

5.3 基本的な使い方 — kubectl操作ガイド

#!/bin/bash
# k8s_guide.sh — Kubernetes基本操作リファレンス

# ============================================
# 1. リソースの適用(マニフェストの適用)
# ============================================
kubectl apply -f deployment.yaml        # 単一ファイル適用
kubectl apply -f ./manifests/           # ディレクトリ内の全ファイル適用
kubectl apply -f configmap-dev.yaml     # 開発用ConfigMap適用

# ============================================
# 2. リソースの確認
# ============================================
kubectl get pods                        # Pod一覧
kubectl get pods -o wide                # IPやノード情報も表示
kubectl get deployments                 # Deployment一覧
kubectl get services                    # Service一覧
kubectl get all                         # 全リソース一覧
kubectl get all -n prod                 # prod Namespace内の全リソース

# ============================================
# 3. 詳細確認とデバッグ
# ============================================
kubectl describe pod <pod名>            # Podの詳細(イベントログ含む)
kubectl logs <pod名>                    # コンテナログ表示
kubectl logs <pod名> -f                 # ログをリアルタイム追跡
kubectl logs <pod名> -c <コンテナ名>    # マルチコンテナPodの特定コンテナ
kubectl exec -it <pod名> -- /bin/bash   # Pod内にシェル接続

# ============================================
# 4. スケーリング
# ============================================
kubectl scale deployment web-app --replicas=5   # Pod数を5に変更
kubectl autoscale deployment web-app \
  --min=2 --max=10 --cpu-percent=50             # オートスケーリング設定

# ============================================
# 5. 更新とロールバック
# ============================================
kubectl set image deployment/web-app \
  web=nginx:1.28                                # イメージ更新(ローリングアップデート)
kubectl rollout status deployment/web-app       # 更新進捗確認
kubectl rollout history deployment/web-app      # 更新履歴
kubectl rollout undo deployment/web-app         # 前バージョンにロールバック

# ============================================
# 6. リソースの削除
# ============================================
kubectl delete -f deployment.yaml       # ファイル指定で削除
kubectl delete pod <pod名>              # 個別Pod削除(Deploymentが再作成する)
kubectl delete namespace dev            # Namespace丸ごと削除(注意!)

# ============================================
# 7. Namespace操作
# ============================================
kubectl create namespace dev            # Namespace作成
kubectl create namespace prod
kubectl create namespace test
kubectl config set-context --current --namespace=dev  # デフォルトNamespace変更

# ============================================
# 8. ポートフォワード(ローカルからServiceにアクセス)
# ============================================
kubectl port-forward service/web-app-service 8080:80  # localhost:8080でアクセス可能

5.4 実行結果の例

$ minikube start --driver=docker --cpus=2 --memory=4096
😄  minikube v1.35.0 on Ubuntu 24.04 (amd64)
✨  Using the docker driver based on user configuration
📌  Using Docker driver with root privileges
🔥  Creating docker container (CPUs=2, Memory=4096MB) ...
🐳  Preparing Kubernetes v1.35.1 on Docker 27.x ...
🔎  Verifying Kubernetes components...
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster

$ kubectl apply -f deployment.yaml
deployment.apps/web-app created

$ kubectl get pods
NAME                       READY   STATUS    RESTARTS   AGE
web-app-6d8f9b7c4d-2xk9p  1/1     Running   0          30s
web-app-6d8f9b7c4d-7mj3q  1/1     Running   0          30s
web-app-6d8f9b7c4d-bt5nl  1/1     Running   0          30s

$ kubectl apply -f service.yaml
service/web-app-service created

$ kubectl get services
NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP   5m
web-app-service   ClusterIP   10.96.128.42    <none>        80/TCP    10s

5.5 よくあるエラーと対処法

エラー 原因 対処法
ImagePullBackOff コンテナイメージの取得に失敗 kubectl describe podでイメージ名を確認。レジストリのURLやタグが正しいか検証
CrashLoopBackOff コンテナが起動直後にクラッシュし続けている kubectl logs <pod>でアプリのエラーログを確認。環境変数や設定ファイルの不備が多い
Pendingのまま スケジューラがPodを配置できるノードを見つけられない kubectl describe podのEventsを確認。CPUやメモリのrequestsがノードのキャパシティを超えていないか確認
OOMKilled コンテナがメモリ上限(limits.memory)を超えた limits.memoryの値を増やす。またはアプリのメモリ使用量を最適化
CreateContainerConfigError ConfigMapやSecretが見つからない 参照しているConfigMap/Secretが同じNamespaceに存在するか確認
node(s) had untolerated taint ノードにtaintが設定されており、PodにtolerationがないPod配置不可 kubectl describe nodeでtaintを確認。必要に応じてtolerationを追加

5.6 環境診断スクリプト

問題が発生した場合は、以下のスクリプトで環境を診断できます。

#!/usr/bin/env python3
"""
Kubernetes環境診断スクリプト
実行方法: python check_k8s_env.py
前提: kubectl がインストール済みで、クラスタに接続済み
"""

import subprocess
import shutil
import json
import sys


def run_cmd(cmd):
    """コマンドを実行して結果を返す"""
    try:
        result = subprocess.run(
            cmd, shell=True, capture_output=True, text=True, timeout=15
        )
        return result.returncode, result.stdout.strip(), result.stderr.strip()
    except subprocess.TimeoutExpired:
        return -1, "", "タイムアウト"
    except Exception as e:
        return -1, "", str(e)


def check_k8s_environment():
    """Kubernetes環境を総合チェック"""
    issues = []
    warnings = []

    print("=" * 60)
    print("Kubernetes 環境診断レポート")
    print("=" * 60)

    # --- 1. kubectl の存在確認 ---
    print("\n[1/6] kubectl のインストール確認...")
    if shutil.which("kubectl"):
        rc, out, _ = run_cmd("kubectl version --client -o json")
        if rc == 0:
            ver = json.loads(out)
            git_ver = ver.get("clientVersion", {}).get("gitVersion", "不明")
            print(f"  ✅ kubectl {git_ver}")
        else:
            issues.append("kubectl はあるがバージョン取得に失敗")
    else:
        issues.append("kubectl がインストールされていません")

    # --- 2. クラスタ接続確認 ---
    print("\n[2/6] クラスタ接続確認...")
    rc, out, err = run_cmd("kubectl cluster-info")
    if rc == 0:
        lines = out.split("\n")
        for line in lines[:2]:
            print(f"{line}")
    else:
        issues.append(f"クラスタに接続できません: {err}")

    # --- 3. ノード状態確認 ---
    print("\n[3/6] ノード状態確認...")
    rc, out, _ = run_cmd("kubectl get nodes -o json")
    if rc == 0:
        nodes = json.loads(out)
        for node in nodes.get("items", []):
            name = node["metadata"]["name"]
            conditions = node["status"].get("conditions", [])
            ready = any(
                c["type"] == "Ready" and c["status"] == "True" for c in conditions
            )
            version = node["status"]["nodeInfo"]["kubeletVersion"]
            if ready:
                print(f"{name} — Ready (K8s {version})")
            else:
                issues.append(f"ノード {name} が NotReady 状態")
                print(f"{name} — NotReady")
    else:
        issues.append("ノード情報の取得に失敗")

    # --- 4. Pod状態チェック ---
    print("\n[4/6] Pod状態チェック (全Namespace)...")
    rc, out, _ = run_cmd(
        "kubectl get pods --all-namespaces -o json"
    )
    if rc == 0:
        pods = json.loads(out)
        total = len(pods.get("items", []))
        problem_pods = []
        for pod in pods.get("items", []):
            phase = pod["status"].get("phase", "Unknown")
            name = pod["metadata"]["name"]
            ns = pod["metadata"]["namespace"]
            if phase not in ("Running", "Succeeded"):
                problem_pods.append(f"{ns}/{name} ({phase})")
        print(f"  Pod総数: {total}")
        if problem_pods:
            warnings.append(
                f"正常でないPod: {len(problem_pods)}"
            )
            for p in problem_pods[:5]:
                print(f"  ⚠️  {p}")
        else:
            print("  ✅ 全Pod正常稼働中")

    # --- 5. リソース使用状況 ---
    print("\n[5/6] リソース使用状況...")
    rc, out, _ = run_cmd("kubectl top nodes")
    if rc == 0:
        print(f"  {out}")
    else:
        warnings.append("Metrics Serverが未導入のためリソース使用量を取得できません")
        print("  ⚠️  kubectl top にはMetrics Serverが必要です")
        print("  💡 minikube: minikube addons enable metrics-server")

    # --- 6. GPU リソース確認 ---
    print("\n[6/6] GPU リソース確認...")
    rc, out, _ = run_cmd(
        'kubectl get nodes -o jsonpath=\'{range .items[*]}{.metadata.name}{"  GPU: "}{.status.allocatable.nvidia\\.com/gpu}{"\\n"}{end}\''
    )
    if rc == 0 and "GPU:" in out:
        lines = [l for l in out.split("\n") if l.strip()]
        for line in lines:
            if "GPU: " in line and line.split("GPU: ")[1].strip():
                print(f"{line.strip()}")
            else:
                print(f"  ℹ️  {line.strip()} (GPUリソースなし)")
    else:
        print("  ℹ️  NVIDIA Device Pluginが未導入、またはGPUノードなし")

    # --- 結果サマリー ---
    print("\n" + "=" * 60)
    if issues:
        print("❌ 問題が見つかりました:")
        for issue in issues:
            print(f"  - {issue}")
    if warnings:
        print("⚠️  警告:")
        for w in warnings:
            print(f"  - {w}")
    if not issues and not warnings:
        print("✅ 環境は正常です。Kubernetesクラスタは稼働中です。")
    print("=" * 60)


if __name__ == "__main__":
    check_k8s_environment()

実装方法がわかったので、次は具体的なユースケースを見ていきます。


6. ユースケース別ガイド

6.1 ユースケース1: GPU対応AI推論サービスのデプロイ

想定読者: GPU環境でOllama等のLLM推論サービスをKubernetes上で動かしたい方

推奨構成: NVIDIA Device Plugin + Deployment + Service

KubernetesでGPUを使うには、NVIDIA Device Pluginをクラスタにインストールし、Podのresourcesnvidia.com/gpuを要求します。

v1.34でGA(安定版)になったDynamic Resource Allocation(DRA) は、GPUの部分割り当てやトポロジ考慮スケジューリングを可能にする新機能です。従来のDevice Pluginより柔軟ですが、2026年3月時点ではNVIDIA DRA Driverはまだプレビュー段階のため、本記事では従来のDevice Plugin方式を紹介します。

サンプルコード — GPU推論サービス(Ollama):

# gpu-ai-stack.yaml — GPU対応AI推論サービス一式

# --- 1. Namespace ---
apiVersion: v1
kind: Namespace
metadata:
  name: ai-inference
---

# --- 2. PersistentVolumeClaim(モデルデータの永続化) ---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ollama-models-pvc
  namespace: ai-inference
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi          # LLMモデルは大きい

---

# --- 3. Ollama Deployment(GPU付き) ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama
  namespace: ai-inference
spec:
  replicas: 1                 # GPU推論は通常1レプリカ
  selector:
    matchLabels:
      app: ollama
  template:
    metadata:
      labels:
        app: ollama
    spec:
      containers:
      - name: ollama
        image: ollama/ollama:latest
        ports:
        - containerPort: 11434
        resources:
          requests:
            cpu: "2"
            memory: "8Gi"
            nvidia.com/gpu: "1"   # GPU 1枚を要求
          limits:
            cpu: "4"
            memory: "16Gi"
            nvidia.com/gpu: "1"
        volumeMounts:
        - name: models
          mountPath: /root/.ollama
        readinessProbe:
          httpGet:
            path: /api/tags
            port: 11434
          initialDelaySeconds: 10
          periodSeconds: 10
      volumes:
      - name: models
        persistentVolumeClaim:
          claimName: ollama-models-pvc

---

# --- 4. Ollama Service ---
apiVersion: v1
kind: Service
metadata:
  name: ollama-service
  namespace: ai-inference
spec:
  selector:
    app: ollama
  ports:
  - port: 11434
    targetPort: 11434
  type: ClusterIP

---

# --- 5. Open WebUI Deployment ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-webui
  namespace: ai-inference
spec:
  replicas: 2                 # WebUIはスケール可能
  selector:
    matchLabels:
      app: open-webui
  template:
    metadata:
      labels:
        app: open-webui
    spec:
      containers:
      - name: webui
        image: ghcr.io/open-webui/open-webui:main
        ports:
        - containerPort: 8080
        env:
        - name: OLLAMA_BASE_URL
          value: "http://ollama-service:11434"
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1"
            memory: "1Gi"

---

# --- 6. Open WebUI Service(外部公開) ---
apiVersion: v1
kind: Service
metadata:
  name: open-webui-service
  namespace: ai-inference
spec:
  selector:
    app: open-webui
  ports:
  - port: 8080
    targetPort: 8080
  type: NodePort              # 開発環境向け。本番ではLoadBalancerかIngress
# デプロイ手順
kubectl apply -f gpu-ai-stack.yaml

# GPU割り当て確認
kubectl describe pod -n ai-inference -l app=ollama | grep -A5 "nvidia.com/gpu"

# ポートフォワードでアクセス
kubectl port-forward -n ai-inference service/open-webui-service 8080:8080
# → ブラウザで http://localhost:8080 にアクセス

6.2 ユースケース2: ステートレスWebアプリの本番デプロイ

想定読者: FastAPI / Express等のWebアプリをKubernetesで本番運用したい方

推奨構成: Deployment + Service + HPA(Horizontal Pod Autoscaler)

サンプルコード — オートスケーリング付きWebアプリ:

# web-production.yaml — 本番Webアプリ構成

# --- 1. Namespace ---
apiVersion: v1
kind: Namespace
metadata:
  name: prod

---

# --- 2. Deployment ---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-server
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1             # 更新時に1つ多くPodを作る
      maxUnavailable: 0       # 更新中に利用不可のPodをゼロに
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
      - name: api
        image: myregistry/api-server:v1.2.0
        ports:
        - containerPort: 8000
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secret
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "1"
            memory: "512Mi"
        readinessProbe:       # トラフィックを受ける準備ができたか
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:        # コンテナが生きているか
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 15
          periodSeconds: 10
          failureThreshold: 3

---

# --- 3. Service ---
apiVersion: v1
kind: Service
metadata:
  name: api-service
  namespace: prod
spec:
  selector:
    app: api-server
  ports:
  - port: 80
    targetPort: 8000
  type: LoadBalancer

---

# --- 4. HPA(Horizontal Pod Autoscaler) ---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server-hpa
  namespace: prod
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60    # CPU使用率60%を超えたらスケールアウト
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300   # 5分間安定してからスケールダウン

readinessProbelivenessProbeの違いは重要です。readinessProbeが失敗するとServiceからトラフィックが外されます(Pod自体は生き続ける)。livenessProbeが失敗するとPodが再起動されます。どちらも必ず設定しましょう。

6.3 ユースケース3: In-Place Pod Resource Resize(v1.35 GA新機能)

想定読者: AI推論サービスなど、Podの再起動コストが高いワークロードを運用している方

推奨構成: Deployment + In-Place Resize(resizePolicyフィールド)

Kubernetes v1.35でIn-Place Pod Resource ResizeがGA(安定版)になりました。従来、Podのリソース(CPU/メモリ)を変更するにはPodの再作成が必要でした。AI推論サーバーのように「起動に数十秒かかる」「GPUメモリにモデルをロード済み」のワークロードでは、この再起動は致命的です。

v1.35以降は、Podを動かしたままCPUやメモリの割り当てを変更できます。

サンプルコード — リサイズ対応Deployment:

# resize-demo.yaml — In-Place Resize対応のDeployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inference-server
  namespace: ai-inference
spec:
  replicas: 1
  selector:
    matchLabels:
      app: inference-server
  template:
    metadata:
      labels:
        app: inference-server
    spec:
      containers:
      - name: inference
        image: myregistry/inference:v2.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "2"
            memory: "4Gi"
          limits:
            cpu: "4"
            memory: "8Gi"
        resizePolicy:                # v1.35 新フィールド
        - resourceName: cpu
          restartPolicy: NotRequired # CPU変更時に再起動不要
        - resourceName: memory
          restartPolicy: NotRequired # メモリ変更時も再起動不要
# 適用
kubectl apply -f resize-demo.yaml

# 稼働中にリソースを変更(Podは再起動されない)
kubectl patch pod <pod名> -n ai-inference --subresource resize --patch \
  '{"spec":{"containers":[{"name":"inference","resources":{"requests":{"cpu":"4","memory":"8Gi"},"limits":{"cpu":"8","memory":"16Gi"}}}]}}'

# リサイズの進捗確認
kubectl get pod <pod名> -n ai-inference -o jsonpath='{.status.resize}'
# → "InProgress" → "Completed" と遷移

In-Place Resizeには制約があります。QoSクラス(Guaranteed / Burstable / BestEffort)が変わるリサイズはブロックされます。Guaranteedクラスの場合、requestsとlimitsを同時に変更してください。

ユースケースを把握できたところで、この先の学習パスを確認しましょう。


7. 学習ロードマップ

この記事を読んだ後、次のステップとして以下をおすすめします。

初級者向け(まずはここから)

  1. Kubernetes公式チュートリアル — ブラウザ内でK8sを試せるインタラクティブ環境あり
  2. minikubeで本記事のサンプルを全て動かす — 「apply → get → describe → logs → delete」のサイクルを体に覚えさせる
  3. kubectl チートシート — 日常的に使うコマンドを整理

中級者向け(実践に進む)

  1. Helm — K8sのパッケージマネージャ。マニフェストをテンプレート化してパラメータ管理
  2. Kustomize — 環境差分管理。本記事のConfigMap分離をさらに体系的に
  3. Ingress / Gateway API — 外部トラフィックのルーティング。v1.35でIngress NGINXが非推奨に、Gateway APIへの移行が進行中
  4. StatefulSet — データベース等のステートフルワークロード管理

上級者向け(さらに深く)

  1. Operator パターン — CRD(Custom Resource Definition)で独自リソースを定義し、アプリ固有の運用ロジックをKubernetes上に実装
  2. Dynamic Resource Allocation(DRA) — GPU等の特殊リソースの柔軟な割り当て。NVIDIA DRA Driverの導入
  3. Gang Scheduling / Kueue — AI分散学習ジョブの「全部揃ってから実行」制御とジョブキューイング
  4. Kubernetes ソースコードリーディング — Go言語で書かれたK8sの内部実装を読む

8. まとめ

この記事では、Kubernetesについて以下を解説しました。

  1. なぜKubernetesが必要かDocker Composeの「単一マシン」の限界と、複数マシンにまたがるオーケストレーションの必要性
  2. 歴史と背景 — Google Borg → オーケストレーション戦争 → K8sの勝利 → v1.35 "Timbernetes"の最新機能
  3. コアコンセプト — Pod、Deployment、Service、Namespace、ConfigMap/Secret の関係性と「宣言的管理」の思想
  4. 実践 — minikubeでのローカル環境構築、kubectl操作、環境別ConfigMap分離
  5. ユースケース — GPU対応AI推論サービス、オートスケーリングWebアプリ、In-Place Pod Resource Resize

私の所感

本シリーズではLinuxUbuntuWSLDockerDocker Compose → Kubernetesと、コンテナ基盤技術を一気通貫で辿ってきました。

正直に言うと、Kubernetesは「学習コストが高い」技術です。概念の多さ、YAMLの量、トラブルシューティングの難しさ — 最初は私も圧倒されました。しかし、Docker Composeで「複数コンテナの管理」を経験した人なら、Kubernetesの思想は自然に理解できるはずです。なぜならKubernetesは、Composeの「宣言的にサービスを定義する」思想を、複数マシン・自動スケーリング・自己回復にまで拡張したものだからです。

RTX 5090環境でOllamaを動かす程度ならDocker Composeで十分です。しかし「このサービスを他の人にも使ってもらいたい」「24時間365日止めたくない」「トラフィックの増減に自動で対応したい」 — そう思った瞬間、Kubernetesの出番です。

v1.35のIn-Place Pod Resource Resizeは、AI推論サービスの運用を劇的に楽にする可能性を秘めています。そしてGang SchedulingやDRAの進化は、GPUリソースの効率的な共有を現実のものにしつつあります。2026年のKubernetesは、もはやWebサービスだけのプラットフォームではありません。AI/MLの基盤OSへと進化しています。

このシリーズが、皆さんのコンテナ技術への理解の一助になれば幸いです。


シリーズ全記事リンク

本記事は「インフラ技術を一気通貫で学ぶ」シリーズの最終回です。

No. トピック リンク
1 Linux Linuxってなんだ?
2 Ubuntu Ubuntuってなんだ?
3 WSL WSLってなんだ?
4 Docker Dockerってなんだ?
5 Docker Compose Docker Composeってなんだ?
6 Kubernetes 本記事

参考文献


🐦 X (Twitter): @geneLab_999

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?