mcpField
D
docker-best-practices

docker-best-practices

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

docker-best-practices について

Docker Best Practices は、Python バックエンドや React フロントエンドの Docker 利用を支援するガイドです。イメージ構築、Compose によるローカル開発、セキュリティ強化、スキャン、タグ付け、トラブル対応を扱います。

主な機能

  1. 01マルチステージビルドとイメージ最適化
  2. 02Python・React 向けイメージの指針
  3. 03Docker Compose によるローカル開発
  4. 04コンテナの強化と Trivy スキャン
  5. 05イメージのタグ付け戦略

活用シーン

  1. 01Python バックエンドの Dockerfile 作成
  2. 02イメージ縮小とビルドキャッシュ改善
  3. 03Compose のローカル開発環境の設定
  4. 04イメージの脆弱性スキャンとタグ計画

インストール

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

$npx skills add https://github.com/hieutrtr/ai1-skills --skill docker-best-practices

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
docker-compose-template.yml
python-dockerfile-template
react-dockerfile-template

詳細

Docker のベストプラクティス

使用するタイミング

次の場合にこのスキルを有効にします:

  • Python バックエンドまたは React フロントエンド用の新しい Dockerfile を作成するとき
  • 既存の Docker イメージを最適化してサイズを縮小したり、ビルドを高速化したりするとき
  • ローカル開発用に Docker Compose を設定するとき
  • ビルド時の依存関係と実行時の依存関係を分離するため、マルチステージビルドを設定するとき
  • コンテナのセキュリティを強化するとき(非 root ユーザー、最小限のベースイメージ)
  • Trivy で Docker イメージのセキュリティスキャンを実行するとき
  • CI/CD パイプライン用のイメージタグ付け戦略を設計するとき
  • Docker のビルド失敗や実行時の問題をトラブルシューティングするとき

次の場合はこのスキルを使用しないでください:

  • デプロイのオーケストレーションまたは CI/CD パイプライン(deployment-pipeline を使用してください)
  • Kubernetes の設定または Helm チャート
  • クラウドインフラストラクチャのプロビジョニング(Terraform、CloudFormation)
  • アプリケーションコードのパターン(python-backend-expert または react-frontend-expert を使用してください)

手順

マルチステージビルド戦略

マルチステージビルドでは、ビルド時の依存関係と実行時の依存関係を分離することで、最終イメージを小さく保てます。

原則: フルイメージでビルドし、最小限のイメージで実行します。実行時に必要なものだけをコピーします。

┌──────────────────────────────────┐
│       Stage 1: Builder           │
│  Full SDK, build tools, deps     │
│  Compile, install, build         │
├──────────────────────────────────┤
│       Stage 2: Runtime           │
│  Minimal base image              │
│  COPY --from=builder artifacts   │
│  Non-root user, health check     │
└──────────────────────────────────┘
Python バックエンドの Dockerfile

完全なテンプレートについては、references/python-dockerfile-template を参照してください。

Python に関する主な判断事項:

# Stage 1: Build dependencies
FROM python:3.12-slim AS builder

WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential libpq-dev \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Stage 2: Runtime
FROM python:3.12-slim AS runtime

# Install only runtime system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 curl \
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

WORKDIR /app
COPY --from=builder /install /usr/local
COPY src/ ./src/
COPY alembic/ ./alembic/
COPY alembic.ini .

RUN chown -R appuser:appuser /app
USER appuser

EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

これらの選択をする理由:

  • alpine ではなく python:3.12-slim を使用することで、バイナリホイールとの musl 互換性の問題を回避できます
  • --no-cache-dir により、pip のキャッシュでイメージが肥大化するのを防ぎます
  • --prefix=/install により、インストール済みパッケージを分離し、クリーンに COPY できます
  • 実行時には libpq5 を、ビルド時にのみ libpq-dev を使用して、実行時の依存関係を最小限に抑えます
  • HEALTHCHECK コマンドに必要なため、実行時に curl を使用します
React フロントエンドの Dockerfile

完全なテンプレートについては、references/react-dockerfile-template を参照してください。

React に関する主な判断事項:

# Stage 1: Build
FROM node:20-alpine AS builder

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY . .
RUN npm run build

# Stage 2: Serve with Nginx
FROM nginx:alpine AS runtime

COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup && \
    chown -R appuser:appgroup /var/cache/nginx /var/log/nginx /etc/nginx/conf.d && \
    touch /var/run/nginx.pid && chown appuser:appgroup /var/run/nginx.pid

USER appuser
EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD wget -q --spider http://localhost:8080/ || exit 1

CMD ["nginx", "-g", "daemon off;"]

これらの選択をする理由:

  • ビルドには node:20-alpine を使用します。Node イメージの中で最小であり、ビルド時にのみ必要です
  • 配信には nginx:alpine を使用します。ベースサイズは約 7MB で、本番環境向けの静的ファイルサーバーです
  • npm ci はロックファイルに基づいて確実にインストールでき、npm install より高速です
  • --ignore-scripts はセキュリティ対策で、インストール時に任意のスクリプトが実行されるのを防ぎます
  • 最終イメージには Node.js の実行環境は含まれません。静的ファイルと Nginx のみです
ベースイメージの選択ガイド
使用例ベースイメージサイズ備考
Python バックエンドpython:3.12-slim約 150MBバイナリホイールとの互換性が最も高い
Python バックエンド(最小構成)python:3.12-alpine約 50MB一部のパッケージでは musl の回避策が必要になる場合があります
React のビルドステージnode:20-alpine約 130MBビルド時にのみ使用
React の実行環境nginx:alpine約 7MB本番環境での静的ファイル配信
ユーティリティ/スクリプトalpine:3.19約 5MB補助コンテナ用

ルール:

  1. latest タグは使用せず、常にメジャーおよびマイナーバージョンを固定します
  2. Python では -slim バリアントを優先します(musl の問題を回避できます)
  3. Node.js と Nginx では -alpine バリアントを優先します(イメージが小さくなります)
  4. セキュリティパッチを適用するため、ベースイメージを毎月更新します
レイヤーの最適化

Docker はレイヤーをキャッシュします。変更頻度の低い命令から高い命令の順に記述します。

最適なレイヤーの順序:

# 1. Base image (changes rarely)
FROM python:3.12-slim

# 2. System dependencies (changes monthly)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq5 curl && rm -rf /var/lib/apt/lists/*

# 3. Create user (changes never)
RUN groupadd -r appuser && useradd -r -g appuser appuser

# 4. Python dependencies (changes weekly)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 5. Application code (changes every commit)
COPY src/ ./src/

# 6. Runtime config (changes rarely)
USER appuser
EXPOSE 8000
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

避けるべきよくある間違い:

# BAD: Copying everything before installing dependencies (busts cache)
COPY . .
RUN pip install -r requirements.txt

# GOOD: Copy only requirements first, then install, then copy code
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src/ ./src/

レイヤーを最小限にする:

# BAD: Multiple RUN commands create multiple layers
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# GOOD: Single RUN command, single layer, clean up in same layer
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    && rm -rf /var/lib/apt/lists/*
.dockerignore

不要なファイルがビルドコンテキストに含まれないよう、常に .dockerignore を追加します。

# Version control
.git
.gitignore

# Python
__pycache__
*.pyc
*.pyo
.pytest_cache
.mypy_cache
.ruff_cache
*.egg-info
dist/
build/
.venv/
venv/

# Node
node_modules/
npm-debug.log*
.next/
coverage/

# IDE
.vscode/
.idea/
*.swp
*.swo

# Docker
Dockerfile*
docker-compose*
.dockerignore

# Environment files
.env
.env.*
!.env.example

# Documentation
*.md
docs/
LICENSE

# CI/CD
.github/
.gitlab-ci.yml

# OS
.DS_Store
Thumbs.db

.dockerignore の効果:

  • 使用しない場合:ビルドコンテキストが 500MB 以上になることがあります(node_modules、.git)
  • 使用する場合:ビルドコンテキストは通常 5~20MB です
  • ビルドが高速化し、.env ファイルからシークレットが漏えいするリスクもありません
セキュリティの強化
非 root ユーザー

本番環境でコンテナを root として実行しないでください。

# Create a dedicated user with no shell and no home directory
RUN groupadd -r appuser && \
    useradd -r -g appuser -d /app -s /sbin/nologin appuser

# Set ownership of application files
COPY --chown=appuser:appuser src/ ./src/

# Switch to non-root user
USER appuser
Trivy によるセキュリティスキャン

デプロイ前にイメージの脆弱性をスキャンします。

# Install Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

# Scan image for vulnerabilities
trivy image --severity HIGH,CRITICAL app-backend:latest

# Scan and fail if HIGH/CRITICAL vulnerabilities found
trivy image --exit-code 1 --severity HIGH,CRITICAL app-backend:latest

# Generate JSON report
trivy image --format json --output trivy-report.json app-backend:latest

# Scan Dockerfile for misconfigurations
trivy config Dockerfile

CI/CD に統合する:

- name: Trivy vulnerability scan
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'app-backend:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'
その他のセキュリティ対策
# Read-only filesystem where possible
# (set at runtime with docker run --read-only)

# No new privileges
# (set at runtime with docker run --security-opt=no-new-privileges)

# Drop all capabilities, add only what is needed
# (set at runtime with docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE)

# Use COPY instead of ADD (ADD can auto-extract tarballs, security risk)
COPY requirements.txt .  # GOOD
# ADD requirements.txt .  # AVOID unless you need tar extraction
ローカル開発用 Docker Compose

完全なテンプレートについては、references/docker-compose-template.yml を参照してください。

アーキテクチャ:

┌────────────┐    ┌────────────┐
│  Frontend  │    │  Backend   │
│ React:3000 │───>│ FastAPI:8000│
└────────────┘    └─────┬──────┘
                        │
                 ┌──────┴──────┐
                 │             │
            ┌────┴────┐  ┌────┴────┐
            │PostgreSQL│  │  Redis  │
            │  :5432   │  │  :6379  │
            └─────────┘  └─────────┘

開発向けの主な Compose 機能:

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.backend
      target: builder  # Use builder stage for development (has dev tools)
    volumes:
      - ./src:/app/src  # Hot reload
    environment:
      - DEBUG=true
      - DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/app_dev
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8000:8000"

  frontend:
    build:
      context: ./frontend
      target: builder
    volumes:
      - ./frontend/src:/app/src  # Hot reload
    ports:
      - "3000:3000"

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]

volumes:
  pgdata:

基本的な Compose パターン:

  • 起動順序を制御するには、depends_on と condition: service_healthy を使用します
  • 開発時のホットリロードのために、ソースコードをボリュームとしてマウントします
  • データベースの永続化には名前付きボリュームを使用します
  • 開発用の依存関係を含むビルドステージを使用するには、target: builder を設定します
  • すべてのインフラストラクチャサービスにヘルスチェックを定義します
イメージのタグ付け戦略

すべての環境で一貫したタグ付け戦略を使用します。

タグの形式:

registry.example.com/app-backend:<tag>

タグ付けのルール:

タグタイミング例目的
git-<sha>ビルドごとgit-a1b2c3d正確なコードへの不変の参照
branch-<name>プッシュごとbranch-mainブランチの最新状態(変更可能)
v<semver>リリース時v1.2.3セマンティックバージョニングによるリリース
latest本番環境へのデプロイ時latest現在の本番環境(変更可能)
stagingステージング環境へのデプロイ時staging現在のステージング環境(変更可能)

実装:

# Build with git SHA tag (immutable)
GIT_SHA=$(git rev-parse --short HEAD)
docker build -t "app-backend:git-${GIT_SHA}" .

# Tag for the branch
BRANCH=$(git rev-parse --abbrev-ref HEAD)
docker tag "app-backend:git-${GIT_SHA}" "app-backend:branch-${BRANCH}"

# Tag for release
docker tag "app-backend:git-${GIT_SHA}" "app-backend:v1.2.3"

# Tag as latest for production
docker tag "app-backend:git-${GIT_SHA}" "app-backend:latest"

ルール:

  1. 常に Git SHA でタグ付けします。これは不変で追跡可能な参照です
  2. latest タグを使ってデプロイしてはいけません。必ず SHA タグを使用します
  3. latest は、本番環境へのデプロイ成功後の便宜的なエイリアスとしてのみ使用します
  4. イメージラベルにビルドメタデータを含めます
# Add metadata labels
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.revision="${GIT_SHA}"
LABEL org.opencontainers.image.created="${BUILD_DATE}"
クイックリファレンス
# Build images
docker build -t app-backend:$(git rev-parse --short HEAD) -f Dockerfile.backend .
docker build -t app-frontend:$(git rev-parse --short HEAD) -f Dockerfile.frontend .

# Start local development
docker compose up -d && docker compose logs -f backend

# Scan for vulnerabilities
trivy image --severity HIGH,CRITICAL app-backend:latest

# Check image sizes
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep app-

# Clean up
docker image prune -f

コメント