KubernetesにおけるPodの定義と特性
Kubernetes環境における全てのオブジェクト同様、Podもリソースモデルの一部として扱われます。これはコンテナを実行するための最小かつ基本的なデプロイ単位であり、通常は1つのインフラストラクチャ用コンテナ(通称Pauseコンテナ)をルートとし、ここに1つ以上のアプリケーションコンテナが配置される構成を取ります。同一Pod内で動作する業務コンテナはIPアドレス、ポート範囲、ファイルシステムを完全に共有し、全体のカナリアステータスは主にインフラコンテナのプロセス死活によって判断されます。
- 単一の論理アプリケーションインスタンスとして機能する
- 常に同一のWorker Node上にスケジュールされ、動的に移動しない(障害時などの再スケジュール時は新しいUIDを持つ同等のPodが置き換えられる)
- ネットワークスタックとストレージボリュームを排他共有する
- KubeletとAPI Serverから直接制御・監視の対象となる
コンテナ直積層ではなくPod抽象化を採用する理由
裸のコンテナを直接デプロイする方が単純に見えますが、オーケストレーション基盤としては情報不足です。Kubernetesはコンテナに対し、再起動時の挙動制御(RestartPolicy)、死活確認(Health Checks)、リソース制限などの運用メタデータを要求します。既存のコンテナ仕様やランタイムの制約に合わせて属性を無理やり拡張するよりも、新規の実体(Pod)として管理ロジックを分離することで、より洗練された自動化とポータビリティが実現できます。
単一Pod内での複数コンテナ統合のメリット
密接な連携が必要なワークロードやSidecarパターン(ログフィルタリング、セキュリティゲートウェイ、メトリクス収集器等)に対応するため、同一Pod内へのマルチコンテナ配置がサポートされています。それぞれの機能を独立したイメージに分割しておくことで、責務の明確化、ログの混線回避、開発チーム間の依存関係の切り離し、イメージの再利用性向上が図れます。同一Pod内のコンテナ間はLoopbackインターフェース経由で通信可能なため、ネットワークオーバーヘッドがほぼゼロになり、SystemVシグナルやPOSIX共有メモリを用いた高速なプロセス間通信も可能です。
共有リソースとLinux Namespaceの仕組み
Pod内部ではLinuxのcgroup、namespace、シグナル伝達などの隔離技術が共通基底となります。具体的には以下のリソースが共有されます:
- ネットワーク: クラスタ内で一意なIPが割り当てられ、全コンテナが同じポート空間を使用します。内部通信は必ずloインターフェースを経由します。外部からのアクセスを受ける場合は、ホストポートのマッピングかServiceリソースによるルーティングが必要です。
- ストレージ: Podレベルで定義されたVolumeを複数のコンテナが同時にマウント可能です。設定ファイルの同期、ログ出力先の一元化、一時データの受け渡しなどに利用されます。
Podマニフェスト(YAML)構造解析
以下は典型的なPod定義ファイルのリファレンス構造です。変数名や検証ロジックを更新し、現代的な運用パターンに準拠させています。
apiVersion: v1 # リソースAPIのバージョン
kind: Pod # オブジェクト種別をPodに指定
metadata:
name: microservice-api # マニフェスト固有の名前
namespace: production # 適用対象のネームスペース
labels:
app: backend # ラベルセレクタ用の識別子
annotations:
maintainer: platform-team # 管理者情報の記録
spec:
restartPolicy: Always # コンテナ終了時の再起動方針(Always/OnFailure/Never)
containers:
- name: api-server # 業務コンテナ名
image: gcr.io/myproject/backend:v2.1
imagePullPolicy: IfNotPresent # プルタイミングの制御
command: ["node"] # エントリーポイントの上書き
args: ["src/server.js"] # 引数リスト
workingDir: /app # 作業ディレクトリ指定
env: # 環境変数の注入
- name: NODE_ENV
value: "production"
- name: LOG_LEVEL
valueFrom: # ConfigMapまたはSecretからの参照
configMapKeyRef:
name: app-config
key: log-level
ports:
- name: http # ポート識別名
containerPort: 3000 # コンテナ側リスニングポート
protocol: TCP
volumeMounts:
- name: shared-data # ボリュームマウント先名称
mountPath: /app/data # 物理パスとの対応
readOnly: false
resources: # CPU/Memoryの制限値と予約量
limits:
cpu: "1" # 最大使用CPUコア数
memory: "1Gi" # 最大メモリ使用量
requests:
cpu: "250m"
memory: "512Mi"
livenessProbe: # 死活判定(Liveness)
tcpSocket:
port: 3000
initialDelaySeconds: 15 # 初期待機秒数
periodSeconds: 10 # 判定間隔
timeoutSeconds: 3
failureThreshold: 3 # 故障と見なす連続失敗回数
readinessProbe: # トラフィック受信可否(Readiness)
exec:
command: ["cat", "/tmp/healthy"]
securityContext: # コンテナ実行権限の設定
runAsNonRoot: true # rootユーザー以外での実行強制
readOnlyRootFilesystem: true # ルートfsの読み取り専用化
volumes: # Pod共有ボリュームの定義
- name: shared-data
emptyDir: # 一時的なデータ保存用
medium: Memory # RAMディスクとして確保
sizeLimit: 100Mi # 容量上限
- name: cert-volume
secret: # Secretオブジェクトから証明書取得
secretName: tls-cert # 参照するSecret名
defaultMode: 0400 # ファイルパーミッション設定
Podの管理パターンとライフサイクル
Kubernetes上でのPod管理は主に2つのモードに大別されます:
- スタンドアロン(独立型): 直接作成されるとSchedulerによりNodeへ配置されますが、Controllerによる自動修復機能は付与されません。ノード障害やリソース枯渇時にPodは削除済み扱いとなり、手動での再作成が必要です。バッチ処理や一時的なテスト用途に適しています。
- コントローラー管理型: DeploymentやStatefulSetなどのHigher-level Controllerが背後でReplicaセットを監視し、レプリカ数の恒常化、ローリングアップデート、エラーからの自動復帰を担います。本番環境における標準運用フローとなります。
優雅な終了処理(Graceful Termination)
プロセスの強制終了(SIGKILL)によるデータ破損やコネクション切断を防ぐため、完了手順(Termination Lifecycle)が厳密に定義されています。ユーザがDelete操作を行うと、デフォルトで30秒の猶予期間(Grace Period)が開始されます。
- kubeletはPodの主プロセスへSIGTERM信号を送信し、シャットダウン準備を促します。
preStopフックが定義されている場合、ここでは遅延時間や追加のクリーンアップタスクを実行します。- Serviceエンドポイントから該当PodのIPが除外され、既存の接続完了待ちが発生します。
- 猶予時間を過ぎた段階でSIGKILLを発行し、コンテナランタイムによりプロセスツリーを一括殺します。
kubectl delete pod <name> --grace-period=0 --force を実行すると、APIサーバー側の登録情報を即時抹消しますが、実際のNode上のクリーンアップまでラグが生じる点と、保留中のI/O処理が中断される点に留意が必要です。
インフラコンテナ(Pause/Infra)の役割
各Podの最初期に起動し、他のコンテナにとっての「仮想ホスト」的役割を果たします。主な任務はネームスペースの初期生成と、ゾンビプロセスの回収Initプロセスとしての機能です。CRI(Container Runtime Interface)の実装やKubeletの設定オプションによってはPID共有が有効化されていないケースもあり、その際は各コンテナが独自にinitプロセスを持つ構成となります。
Dockerランタイム上でPodの内部構造をシミュレートする場合、以下のコマンドチェーンが該当します。インフラコンテナを起点に業務コンテナをネームスペースに接着している様子が確認できます。
# 1. インフラ層コンテナの起動(Network/PID/IPC NameSpaceの提供)
docker run -d \
--name infra-proxy \
--ipc=shareable \
--publish 9090:80 \
registry.cn-hangzhou.aliyuncs.com/google_containers/pause:latest
# 2. プロキシ用コンテナの接着(同じNetwork/IPC/PID Spaceへ参加)
docker run -d \
--name http-gateway \
-v ./gateway.conf:/etc/nginx/conf.d/default.conf \
--network container:infra-proxy \
--ipc container:infra-proxy \
--pid container:infra-proxy \
nginx:alpine
# 3. バックエンド用コンテナの接着
docker run -d \
--name worker-node \
--network container:infra-proxy \
--ipc container:infra-proxy \
--pid container:infra-proxy \
myapp-backend:v3.0.1
上記シナリオでは、infra-proxy がネットワークスタックとinitプロセスを提供し、http-gateway と worker-node はそれらの共有空間に属すことで、localhost通信とシグナル伝達が透過的に行えるようになっています。
Pod間で共有されるNamespace一覧
- PID Namespace: Pod配下のコンテナ間でプロセスIDテーブルを共有し、相互のプロセス監視とシグナル送信が可能になる
- Network Namespace: 同一のIPアドレス、ARPテーブル、iptablesルール、ルートテーブルを共用する
- IPC Namespace: SystemVメッセージキュー、セマフォ、共有メモリ領域を跨いでアクセス可能
- UTS Namespace: ホスト名の同一化を実施し、DNS逆引きやログタグにおける識別子の統一を図る
- Volumes: Podスコープで宣言されたStorage ClassやEmptyDirを、各コンテナのファイルシステムに重ねてマウントする