目次


1. イメージ作成(Dockerfile)

ベースイメージ

  • 公式イメージや検証済みのイメージを使う
  • alpine、slim、distroless など軽量なものを選ぶ
  • latest ではなくバージョンタグで固定する(例: node:22-slim)。厳密に固定したいときはダイジェスト(@sha256:...)を指定する

マルチステージビルド

ビルド用ステージと実行用ステージを分け、最終イメージには実行に必要なものだけを入れる。

FROM golang:1.23 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app
 
FROM gcr.io/distroless/static
COPY --from=build /app /app
USER nonroot
ENTRYPOINT ["/app"]

レイヤーキャッシュの活用

変更の少ないものから順に COPY する。まず依存定義ファイルをコピーしてインストールし、その後にソースコードをコピーする。

COPY package.json package-lock.json ./
RUN npm ci
COPY . .
  • 関連する RUN は && でまとめ、同じレイヤー内で一時ファイルも削除する

    RUN apt-get update \
        && apt-get install -y --no-install-recommends curl \
        && rm -rf /var/lib/apt/lists/*
  • BuildKit のキャッシュマウント(RUN --mount=type=cache,...)を使うと、パッケージのダウンロードを高速化できる

.dockerignore

.git、node_modules、.env、ログ、ビルド成果物などを除外する。ビルドが速くなり、秘密情報の混入も防げる。

.git
node_modules
.env
*.log
dist

その他

  • 単純なファイルのコピーには ADD ではなく COPY を使う
  • CMD と ENTRYPOINT は exec 形式(["cmd", "arg"])で書く。こうするとシグナルが正しく伝わる
  • WORKDIR を明示し、cd は使わない
  • LABEL でメタデータ(バージョン、メンテナなど)を付ける

2. セキュリティ

  • root で動かさず、USER で非特権ユーザーに切り替える
  • 秘密情報をイメージに含めない
    • ENV や COPY で入れない
    • ビルド時は RUN --mount=type=secret を使う
    • 実行時は環境変数やシークレット管理ツールで渡す
  • Trivy や Docker Scout などでイメージの脆弱性を定期的にスキャンする
  • 不要なパッケージやツールを入れない(攻撃対象を減らす)
  • 実行時は必要最小限の権限に絞る
    • --read-only
    • --cap-drop ALL(必要なものだけ --cap-add)
    • --security-opt no-new-privileges
  • --privileged や Docker ソケット(/var/run/docker.sock)のマウントはできるだけ避ける
  • 必要に応じてイメージに署名する(cosign など)

3. コンテナ設計・運用

  • 1コンテナにつき1つの関心事を扱う(Web と DB は分ける)
  • コンテナはステートレスにし、永続データは volume に置く
  • 設定は環境変数で外から注入する(12-Factor App の考え方)
  • ログはファイルではなく stdout/stderr に出力する
  • HEALTHCHECK やオーケストレーターのヘルスチェックを設定する
  • SIGTERM を受けたら正常に終了するようにする。PID 1 問題には --init や tini で対処する
  • --memory、--cpus でリソース上限を設定する
  • 再起動ポリシー(--restart unless-stopped など)を設定する

4. Docker Compose / 開発環境

  • 開発用と本番用で設定を分ける(compose.override.yaml やプロファイルを使う)

  • depends_on に condition: service_healthy を付け、起動順をヘルスチェックで制御する

    services:
      app:
        depends_on:
          db:
            condition: service_healthy
      db:
        image: postgres:17
        healthcheck:
          test: ["CMD", "pg_isready", "-U", "postgres"]
          interval: 5s
          retries: 5
  • 開発時はソースをバインドマウントし、本番ではイメージに焼き込む

5. CI/CD

  • イメージは一度だけビルドし、同じイメージを各環境に昇格させる
  • タグには Git の SHA やセマンティックバージョンを使い、追跡できるようにする
  • hadolint で Dockerfile を lint し、脆弱性スキャンもパイプラインに組み込む
  • 複数アーキテクチャ(amd64/arm64)が必要なら docker buildx でビルドする

優先度の目安

まず効果が大きいのは次の4つ。

  1. 軽量なベースイメージ+マルチステージビルド
  2. 非 root 実行
  3. 秘密情報をイメージに入れない
  4. .dockerignore の整備

0件のページ