mcpField
D
docker-best-practices

docker-best-practices

github.com/josiahsiegelクラウド・DevOps59939 回インストール19 週間前に更新
リポジトリ

docker-best-practices について

コンテナの開発、デプロイ、運用を扱う、開発者と運用担当者向けのDockerスキルです。イメージ構築、ランタイムのセキュリティ、Compose、性能、運用準備の指針をまとめています。

主な機能

  1. 01ベースイメージとレイヤーの指針
  2. 02マルチステージビルドの実践
  3. 03ランタイムのセキュリティ制御
  4. 04Compose設定のパターン
  5. 05ビルドと実行時の最適化
  6. 06本番運用準備チェックリスト

活用シーン

  1. 01マルチステージビルドによるイメージ縮小
  2. 02コンテナのランタイム設定の強化
  3. 03Composeのサービスとネットワークの設定
  4. 04本番環境に向けたコンテナの準備

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill docker-best-practices

インストール後、Claude Code で/docker-best-practicesを入力して読み込まれたか確認します。

詳細

🚨 重大なガイドライン

Windows のファイルパス要件

必須:Windows ではファイルパスに常にバックスラッシュを使用してください

Windows で Edit ツールまたは Write ツールを使用する場合、ファイルパスにはスラッシュ(/)ではなく、バックスラッシュ(\)を必ず使用してください。

例:

  • ❌ 誤り:D:/repos/project/file.tsx
  • ✅ 正しい:D:\repos\project\file.tsx

これは以下に適用されます。

  • Edit ツールの file_path パラメーター
  • Write ツールの file_path パラメーター
  • Windows システム上でのすべてのファイル操作
ドキュメント作成のガイドライン

ユーザーから明示的に依頼されない限り、新しいドキュメントファイルは作成しないでください。

  • 優先事項:新しいドキュメントを作成するより、既存の README.md ファイルを更新してください
  • リポジトリの整理:ユーザーから依頼されない限り、リポジトリのルートには README.md 以外を置かないでください
  • スタイル:ドキュメントは簡潔で、直接的かつプロフェッショナルなものにしてください。AI が生成したような文体は避けてください
  • ユーザーの希望:ユーザーからドキュメントの作成を明示的に依頼された場合に限り、追加の .md ファイルを作成してください

Docker のベストプラクティス

このスキルでは、コンテナーの開発、デプロイ、運用のあらゆる側面における、最新の Docker のベストプラクティスを紹介します。

イメージのベストプラクティス

ベースイメージの選択

2025 年に推奨される優先順位:

  1. Wolfi/Chainguard(cgr.dev/chainguard/*) - CVE ゼロを目指し、SBOM を含む
  2. Alpine(alpine:3.19) - 約 7MB、最小限の攻撃対象領域
  3. Distroless(gcr.io/distroless/*) - 約 2MB、シェルなし
  4. Slim バリアント(node:20-slim) - 約 70MB、バランスが取れている

主なルール:

  • バージョンタグは必ず正確に指定してください:node:20.11.0-alpine3.19
  • latest は使用しないでください(予測できず、再現性を損ないます)
  • 信頼できるレジストリから公式イメージを使用してください
  • 実際の要件に合ったベースイメージを選んでください
Dockerfile の構成

最適なレイヤーの順序(変更頻度が最も低いものから高いものへ):

1. Base image and system dependencies
2. Application dependencies (package.json, requirements.txt, etc.)
3. Application code
4. Configuration and metadata

理由: Docker はレイヤーをキャッシュします。コードを変更しても依存関係が変わらなければ、キャッシュされた依存関係のレイヤーが再利用され、ビルドが高速化します。

例:

FROM python:3.12-slim

# 1. System packages (rarely change)
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 2. Dependencies (change occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 3. Application code (changes frequently)
COPY . /app
WORKDIR /app

CMD ["python", "app.py"]
マルチステージビルド

マルチステージビルドを使用して、ビルド時の依存関係と実行時の依存関係を分離します。

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:20-alpine AS runtime
WORKDIR /app
# Only copy what's needed for runtime
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
CMD ["node", "dist/server.js"]

メリット:

  • 最終イメージが小さくなります(ビルドツールを含まないため)
  • セキュリティが向上します(攻撃ベクトルが少なくなるため)
  • デプロイが高速化します(アップロード/ダウンロードのサイズが小さくなるため)
レイヤーの最適化

レイヤー数とイメージサイズを減らすために、コマンドをまとめてください。

# Bad - 3 layers, cleanup doesn't reduce size
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Good - 1 layer, cleanup effective
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/*
.dockerignore

不要なファイルを除外するために、必ず .dockerignore を作成してください。

# Version control
.git
.gitignore

# Dependencies
node_modules
__pycache__
*.pyc

# IDE
.vscode
.idea

# OS
.DS_Store
Thumbs.db

# Logs
*.log
logs/

# Testing
coverage/
.nyc_output
*.test.js

# Documentation
README.md
docs/

# Environment
.env
.env.local
*.local

コンテナー実行時のベストプラクティス

セキュリティ
docker run \
  # Run as non-root
  --user 1000:1000 \
  # Drop all capabilities, add only needed ones
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  # Read-only filesystem
  --read-only \
  # Temporary writable filesystems
  --tmpfs /tmp:noexec,nosuid \
  # No new privileges
  --security-opt="no-new-privileges:true" \
  # Resource limits
  --memory="512m" \
  --cpus="1.0" \
  my-image
リソース管理

本番環境では、必ずリソース制限を設定してください。

# docker-compose.yml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 1G
        reservations:
          cpus: '1.0'
          memory: 512M
ヘルスチェック

長時間稼働するすべてのコンテナーにヘルスチェックを実装してください。

HEALTHCHECK --interval=30s --timeout=3s --retries=3 --start-period=40s \
  CMD curl -f http://localhost:3000/health || exit 1

または compose で:

services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
ロギング

ディスクの容量不足を防ぐため、適切なロギングを設定してください。

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

または /etc/docker/daemon.json でシステム全体に設定します。

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
再起動ポリシー
services:
  app:
    # For development
    restart: "no"

    # For production
    restart: unless-stopped

    # Or with fine-grained control (Swarm mode)
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s

Docker Compose のベストプラクティス

ファイル構成
# No version field needed (Compose v2.40.3+)

services:
  # Service definitions
  web:
    # ...
  api:
    # ...
  database:
    # ...

networks:
  # Custom networks (preferred)
  frontend:
  backend:
    internal: true

volumes:
  # Named volumes (preferred for persistence)
  db-data:
  app-data:

configs:
  # Configuration files (Swarm mode)
  app-config:
    file: ./config/app.conf

secrets:
  # Secrets (Swarm mode)
  db-password:
    file: ./secrets/db_pass.txt
ネットワークの分離
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No external access

services:
  web:
    networks:
      - frontend

  api:
    networks:
      - frontend
      - backend

  database:
    networks:
      - backend  # Not accessible from frontend
環境変数
services:
  app:
    # Load from file (preferred for non-secrets)
    env_file:
      - .env

    # Inline for service-specific vars
    environment:
      - NODE_ENV=production
      - LOG_LEVEL=info

    # For Swarm mode secrets
    secrets:
      - db_password

重要:

  • .env を .gitignore に追加してください
  • テンプレートとして .env.example を用意してください
  • シークレットをバージョン管理にコミットしないでください
依存関係の管理
services:
  api:
    depends_on:
      database:
        condition: service_healthy  # Wait for health check
      redis:
        condition: service_started   # Just wait for start

本番環境でのベストプラクティス

イメージのタグ付け戦略
# Use semantic versioning
my-app:1.2.3
my-app:1.2
my-app:1
my-app:latest

# Include git commit for traceability
my-app:1.2.3-abc123f

# Environment tags
my-app:1.2.3-production
my-app:1.2.3-staging
シークレット管理

次のようなことは絶対にしないでください:

# BAD - secret in layer history
ENV API_KEY=secret123
RUN echo "password" > /app/config

次のようにしてください:

# Use Docker secrets (Swarm) or external secret management
docker secret create db_password ./password.txt

# Or mount secrets at runtime
docker run -v /secure/secrets:/run/secrets:ro my-app

# Or use environment files (not in image)
docker run --env-file /secure/.env my-app
モニタリングと可観測性
services:
  app:
    # Health checks
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s

    # Labels for monitoring tools
    labels:
      - "prometheus.io/scrape=true"
      - "prometheus.io/port=9090"
      - "com.company.team=backend"
      - "com.company.version=1.2.3"

    # Logging
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
バックアップ戦略
# Backup named volume
docker run --rm \
  -v VOLUME_NAME:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/backup-$(date +%Y%m%d).tar.gz -C /data .

# Restore volume
docker run --rm \
  -v VOLUME_NAME:/data \
  -v $(pwd):/backup \
  alpine tar xzf /backup/backup.tar.gz -C /data
更新戦略
services:
  app:
    # For Swarm mode - rolling updates
    deploy:
      replicas: 3
      update_config:
        parallelism: 1        # Update 1 at a time
        delay: 10s            # Wait 10s between updates
        failure_action: rollback
        monitor: 60s
      rollback_config:
        parallelism: 1
        delay: 5s

プラットフォーム別のベストプラクティス

Linux
  • セキュリティを強化するため、ユーザー名前空間のリマッピングを使用してください
  • ネイティブのパフォーマンス上の利点を活用してください
  • 最小サイズのイメージには Alpine を使用してください
  • SELinux/AppArmor プロファイルを設定してください
  • Docker デーモンの管理に systemd を使用してください
// /etc/docker/daemon.json
{
  "userns-remap": "default",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "live-restore": true
}
macOS
  • Docker Desktop に十分なリソースを割り当ててください
  • バインドマウントには :delegated または :cached を使用してください
  • ARM(M1/M2)向けのマルチプラットフォームビルドを検討してください
  • ファイル共有を必要なディレクトリに限定してください
# Better volume performance on macOS
volumes:
  - ./src:/app/src:delegated  # Host writes are delayed
  - ./build:/app/build:cached  # Container writes are cached
Windows
  • コンテナーの種類を選択します:Windows または Linux
  • パスにはスラッシュを使用します
  • Docker Desktop でドライブが共有されていることを確認します
  • 改行コードの違い(CRLF と LF)に注意します
  • パフォーマンスを向上させるには、WSL2 バックエンドを検討します
# Windows-compatible paths
volumes:
  - C:/Users/name/app:/app  # Forward slashes work
  # or
  - C:\Users\name\app:/app  # Backslashes need escaping in YAML

パフォーマンスに関するベストプラクティス

ビルドのパフォーマンス
# Use BuildKit (faster, better caching)
export DOCKER_BUILDKIT=1

# Use cache mounts
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

# Use bind mounts for dependencies
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=package-lock.json,target=package-lock.json \
    --mount=type=cache,target=/root/.npm \
    npm ci
イメージサイズ
  • マルチステージビルドを使用します
  • 最小限のベースイメージを選択します
  • 同じレイヤー内でクリーンアップします
  • .dockerignore を使用します
  • ビルド依存関係を削除します
# Install and cleanup in one layer
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    package1 \
    package2 && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
ランタイムのパフォーマンス
# Use exec form (no shell overhead)
CMD ["node", "server.js"]  # Good
# vs
CMD node server.js         # Bad - spawns shell

# Optimize signals
STOPSIGNAL SIGTERM

# Run as non-root (slightly faster, much more secure)
USER appuser

セキュリティに関するベストプラクティスの概要

イメージのセキュリティ:

  • 公式の最小限のベースイメージを使用します
  • 脆弱性をスキャンします(Docker Scout、Trivy)
  • レイヤーにシークレットを含めないでください
  • 非 root ユーザーとして実行します
  • イメージを最新の状態に保ちます

ランタイムのセキュリティ:

  • ケイパビリティを削除します
  • 読み取り専用ファイルシステムを使用します
  • リソース制限を設定します
  • セキュリティオプションを有効にします
  • ネットワークを分離します
  • シークレット管理を使用します

コンプライアンス:

  • CIS Docker Benchmark に準拠します
  • CI/CD でコンテナースキャンを実施します
  • 署名済みイメージを使用します(Docker Content Trust)
  • 監査ログを維持します
  • 定期的にセキュリティレビューを実施します

避けるべき一般的なアンチパターン

❌ 避けること:

  • root として実行する
  • --privileged を使用する
  • Docker ソケットをマウントする
  • latest タグを使用する
  • シークレットをハードコードする
  • ヘルスチェックを省略する
  • リソース制限を無視する
  • サイズの大きなベースイメージを使用する
  • 脆弱性スキャンを省略する
  • 不要なポートを公開する
  • 非効率なレイヤーキャッシュを使用する
  • シークレットを Git にコミットする

✅ 実施すること:

  • 非 root ユーザーとして実行する
  • 最小限のケイパビリティを使用する
  • コンテナーを分離する
  • バージョン付きのタグを付ける
  • シークレット管理を使用する
  • ヘルスチェックを実装する
  • リソース制限を設定する
  • 最小限のイメージを使用する
  • 定期的にスキャンする
  • 最小権限を適用する
  • ビルドキャッシュを最適化する
  • .env.example テンプレートを使用する

本番環境に対応したイメージのチェックリスト

  • 公式の、バージョンが指定された最小限のイメージをベースにしている
  • マルチステージビルドを使用している(該当する場合)
  • 非 root ユーザーとして実行される
  • レイヤーにシークレットが含まれていない
  • .dockerignore が設定されている
  • 脆弱性スキャンに合格している
  • ヘルスチェックが実装されている
  • 適切なラベル(バージョン、説明など)が付いている
  • レイヤーキャッシュが効率的である
  • リソース制限が定義されている
  • ロギングが設定されている
  • シグナルが正しく処理される
  • セキュリティオプションが設定されている
  • ドキュメントが完成している
  • 対象プラットフォームでテスト済みである

このスキルでは、現在の Docker のベストプラクティスを紹介しています。Docker は継続的に進化しているため、最新の推奨事項については必ず公式ドキュメントを確認してください。

コメント