目次
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つ。
- 軽量なベースイメージ+マルチステージビルド
- 非 root 実行
- 秘密情報をイメージに入れない
.dockerignoreの整備