Kubernetes 向け Dockerfile 設計ガイド

はじめに

Dockerfile を「Docker コンテナとして動かす」だけなら、
多くの場合はシンプルな構成でも問題ありません。

しかし Kubernetes(K8s)上で本番運用する Dockerfile には、
Docker 単体とはまったく異なる設計思想が求められます。

Kubernetes 環境では、

  • コンテナは頻繁に再起動される
  • Pod はいつでも破棄・再生成される
  • スケールアウト・ローリングアップデートが前提
  • 死活監視(Probe)が常に動いている

つまり、
「落ちてもすぐ復旧できる」「状態を持たない」コンテナ設計が必須です。

本記事では、

  • Kubernetes 向け Dockerfile に必要な考え方
  • Docker 単体用 Dockerfile との違い
  • やりがちな失敗例
  • Kubernetes を前提とした Dockerfile ハンズオン
  • Deployment での動作確認ポイント

までを、実務視点で丁寧に解説します。


なぜ Kubernetes 向け Dockerfile 設計が重要なのか?

Kubernetes は コンテナを「管理・制御」する仕組みです。
そのため、Dockerfile 側の設計が Kubernetes の思想とズレていると、

  • Pod が頻繁に CrashLoopBackOff になる
  • ローリングアップデートが止まる
  • readinessProbe に失敗し続ける
  • ログが取れず障害調査できない

といった問題が発生します。

👉 Kubernetes は Dockerfile の「甘え」を許してくれない

これが現場でよく言われる理由です。


Kubernetes 向け Dockerfile 設計の基本原則

原則①:1コンテナ = 1プロセス

Kubernetes では、
1つのコンテナで1つの役割だけを持つのが基本です。

❌ nginx + app + cron を同一コンテナ
✅ アプリはアプリ、バッチは別コンテナ


原則②:コンテナは「いつでも死ぬ前提」

  • 再起動される
  • Pod が削除される
  • ノードが落ちる

👉 状態をコンテナ内に保存しない


原則③:標準出力にログを出す

Kubernetes は stdout / stderr を前提にログを収集します。

console.log("server started");

原則④:起動・停止が明確であること

  • 起動が遅すぎない
  • SIGTERM を正しく受け取れる
  • graceful shutdown ができる

Kubernetes で問題になりやすい Dockerfile 例

FROM node:20
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]

一見問題なさそうだが…

  • root 実行
  • マルチステージなし
  • SIGTERM ハンドリング不明
  • readiness/liveness を意識していない

Docker 単体なら動くが、
Kubernetes ではトラブルの元になります。


Kubernetes 向け Dockerfile の改善設計

# ===== Build Stage =====
FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# ===== Runtime Stage =====
FROM node:20-alpine

WORKDIR /app
COPY --from=build /app/dist ./dist

USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

Kubernetes 視点でのポイント

  • マルチステージで軽量化
  • 非 root ユーザー
  • 実行に必要なものだけを残す
  • 起動が速い

ハンズオン①:Kubernetes 向け Node.js アプリを作る

アプリ構成

k8s-app/
├─ Dockerfile
├─ package.json
├─ src/
│  └─ index.js

src/index.js(SIGTERM 対応)

const http = require("http");

const server = http.createServer((req, res) => {
  res.end("Hello Kubernetes!");
});

server.listen(3000);

process.on("SIGTERM", () => {
  console.log("SIGTERM received. shutting down...");
  server.close(() => {
    process.exit(0);
  });
});

👉 Kubernetes が Pod を停止するときに SIGTERM を送る


ハンズオン②:Dockerfile(Kubernetes 対応)

FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]

ハンズオン③:Docker イメージをビルド

docker build -t k8s-app:1.0 .

ハンズオン④:Kubernetes Deployment を作成

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8s-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: k8s-app
  template:
    metadata:
      labels:
        app: k8s-app
    spec:
      containers:
        - name: app
          image: k8s-app:1.0
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10

ハンズオン⑤:Kubernetes にデプロイ

kubectl apply -f deployment.yaml
kubectl get pods

Pod が Running になれば成功です。


Kubernetes 向け Dockerfile で重要な設計ポイント

① 軽量イメージは必須

  • 起動が速い
  • スケールアウトが速い
  • ノード負荷が低い

② コンテナ内で状態を持たない

  • ファイル保存しない
  • セッションは外部(Redis 等)

③ ENTRYPOINT / CMD はシンプルに

CMD ["node", "dist/index.js"]

Kubernetes 側で制御しやすくなる。


④ 停止処理を意識する

  • SIGTERM 対応
  • 処理中リクエストを落とさない

Kubernetes × Dockerfile よくある失敗

  • 起動が遅く readinessProbe 失敗
  • SIGTERM 無視で強制 kill
  • 巨大イメージでスケールが遅い
  • root 実行でセキュリティ指摘

👉 Dockerfile の設計段階でほぼ決まる


Kubernetes 向け Dockerfile チェックリスト

  • マルチステージビルド
  • 非 root ユーザー
  • 軽量ベースイメージ
  • stdout ログ出力
  • SIGTERM 対応
  • readiness / liveness を想定

まとめ

Kubernetes 向け Dockerfile 設計は、

  • Docker 単体とは考え方が違う
  • 「壊れやすさ」を前提にする
  • 運用・自動化・復旧を意識する

ことが重要です。


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です