docker-best-practices について
Docker Best Practices は、Python バックエンドや React フロントエンドの Docker 利用を支援するガイドです。イメージ構築、Compose によるローカル開発、セキュリティ強化、スキャン、タグ付け、トラブル対応を扱います。
主な機能
- 01マルチステージビルドとイメージ最適化
- 02Python・React 向けイメージの指針
- 03Docker Compose によるローカル開発
- 04コンテナの強化と Trivy スキャン
- 05イメージのタグ付け戦略
活用シーン
- 01Python バックエンドの Dockerfile 作成
- 02イメージ縮小とビルドキャッシュ改善
- 03Compose のローカル開発環境の設定
- 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.ymlpython-dockerfile-templatereact-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 | 補助コンテナ用 |
ルール:
latestタグは使用せず、常にメジャーおよびマイナーバージョンを固定します- Python では
-slimバリアントを優先します(musl の問題を回避できます) - Node.js と Nginx では
-alpineバリアントを優先します(イメージが小さくなります) - セキュリティパッチを適用するため、ベースイメージを毎月更新します
レイヤーの最適化
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"
ルール:
- 常に Git SHA でタグ付けします。これは不変で追跡可能な参照です
latestタグを使ってデプロイしてはいけません。必ず SHA タグを使用しますlatestは、本番環境へのデプロイ成功後の便宜的なエイリアスとしてのみ使用します- イメージラベルにビルドメタデータを含めます
# 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