Anthropic ClaudeDevOps・インフラ⭐ リポ 112品質スコア 85/100
docker
Dockerfileの作成・最適化、Docker Composeサービスの設定、ローカル環境と異なる動作をするコンテナのデバッグ、またはPythonおよびNode.jsアプリケーションのイメージサイズ削減が必要な場合に使用します。
description の原文を見る
Use when writing or optimizing Dockerfiles, configuring Docker Compose services, debugging containers that behave differently from local, or reducing image size for Python and Node.js apps.
SKILL.md 本文
Docker パターン
Python と Node.js サービス向けの本番対応 Docker パターン。
いつ使うか
- Dockerfile の作成または最適化(マルチステージ、レイヤーキャッシング)
- Docker Compose サービス、ネットワーク、またはボリュームの設定
- ヘルスチェックまたはスタートアップ依存関係の追加
- シークレットと環境変数の安全な渡し方
- コンテナが起動しない、または Docker とローカルで動作が異なる場合のデバッグ
- イメージサイズの縮小
Dockerfile — Python (FastAPI / uv)
# syntax=docker/dockerfile:1
# --- Build stage ---
FROM python:3.12-slim AS builder
WORKDIR /app
# Install uv
RUN pip install uv --no-cache-dir
# Copy dependency files first — cached unless they change
COPY pyproject.toml uv.lock ./
# Install deps into a prefix (not system), no dev deps
RUN uv sync --frozen --no-dev --prefix /install
# --- Runtime stage ---
FROM python:3.12-slim AS runtime
WORKDIR /app
# Copy installed packages from builder
COPY --from=builder /install /usr/local
# Copy application code last (changes most often)
COPY src/ ./src/
# Non-root user — security best practice
RUN adduser --disabled-password --gecos "" appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
Dockerfile — Node.js (Next.js)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --frozen-lockfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
# Only copy what's needed to run
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
next.config.js でスタンドアロン出力を有効にします:
output: "standalone"
.dockerignore
# Always include these
.git
.gitignore
**/.env
**/.env.*
**/node_modules
**/__pycache__
**/*.pyc
**/*.pyo
.venv
dist
build
.next
coverage
*.log
.DS_Store
レイヤーキャッシング ルール
変更頻度が低い順から高い順にファイルを配置します:
# ✅ 良い例 — pyproject.toml が変わらない限り依存関係がキャッシュされる
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen
COPY src/ ./src/ # code changes don't bust dep layer
# ❌ 悪い例 — コードの変更が依存関係インストールレイヤーをクリアする
COPY . .
RUN uv sync --frozen
キャッシュマウント(BuildKit)— pip/uv キャッシュをイメージに書き込まないようにします:
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
Docker Compose
# docker-compose.yml
services:
api:
build:
context: .
target: runtime # use a specific stage
ports:
- "5003:8000"
environment:
DATABASE_URL: postgresql+asyncpg://user:pass@db:5432/app
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy # wait for health check, not just start
redis:
condition: service_started
restart: unless-stopped
networks:
- backend
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: app
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d app"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
networks:
- backend
redis:
image: redis:7-alpine
command: redis-server --appendonly yes # persist to disk
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
networks:
- backend
volumes:
pg_data:
redis_data:
networks:
backend:
driver: bridge
ヘルスチェック
# Standard health check pattern
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s # how often to check
timeout: 10s # max time per check
retries: 3 # failures before unhealthy
start_period: 30s # grace period before first check counts
FastAPI ヘルスチェック エンドポイント:
@app.get("/health")
async def health():
return {"status": "ok"}
環境変数とシークレット
services:
api:
# Option 1: inline (dev only — visible in docker inspect)
environment:
SECRET_KEY: dev-secret
# Option 2: reference host env var (no value = pass-through)
environment:
SECRET_KEY: ${SECRET_KEY}
# Option 3: .env file (dev only — don't commit secrets)
env_file:
- .env
# Option 4: Docker secrets (production / Swarm)
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
コンテナ内のシークレットは /run/secrets/db_password でアクセスできます。
ネットワーク
networks:
frontend: # API + nginx
backend: # API + DB + Redis (not exposed to frontend network)
services:
nginx:
networks: [frontend]
api:
networks: [frontend, backend] # bridge between networks
db:
networks: [backend] # only reachable from backend
サービス DNS: 同じネットワーク上のコンテナはサービス名で相互に到達できます。
# api コンテナから db に到達する場合:
postgresql://db:5432/mydb # "db" は db コンテナの IP に解決されます
redis://redis:6379
よく使うコマンド
# Build
docker build -t myapp .
docker build --target builder -t myapp:builder . # build specific stage
docker build --no-cache -t myapp . # force rebuild
# Compose
docker compose up -d # start in background
docker compose up --build # rebuild before starting
docker compose down -v # stop + remove volumes
docker compose logs -f api # follow logs for one service
docker compose exec api bash # shell into running container
docker compose ps # status of all services
# Inspect
docker inspect <container> # full config, env vars, mounts
docker stats # live resource usage
docker system df # disk usage by layer/image/volume
# Cleanup
docker system prune -f # remove stopped containers + dangling images
docker volume prune -f # remove unused volumes
docker image prune -a -f # remove all unused images
デバッグ
# Container exits immediately — run it interactively
docker run -it --entrypoint bash myapp
# Check environment inside container
docker exec <container> env
# Copy files out of container
docker cp <container>:/app/logs ./local-logs
# Run with host network (skip Docker networking)
docker run --network host myapp
# Override CMD for one-off
docker compose run --rm api python manage.py migrate
イメージサイズの縮小
| 技法 | 削減量 |
|---|---|
slim/alpine ベースの使用(python:3.12-slim) | フルイメージ比で 60~80% |
| マルチステージビルド — ビルドツールを含めない | 変動 |
--no-install-recommends(apt-get) | 20~40% |
apt キャッシュの削除:rm -rf /var/lib/apt/lists/* | 小 |
--no-cache-dir(pip) | 小 |
.dockerignore でテスト/ドキュメントをスキップ | 小 |
# apt インストール最小パターン
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
注意すべきポイント
- 依存関係インストール前の
COPY . .— ソースコードをすべてコピーするとコード変更のたびに依存関係レイヤーがクリアされます。常にCOPY pyproject.toml uv.lock ./→ インストール →COPY src/ ./の順序にして、マニフェストが変わらない限り依存関係がキャッシュされるようにします - コンテナを root として実行 — コンテナ内のデフォルトユーザーは root です。プロセスエスケープによる攻撃の場合、攻撃者がホスト全体にアクセスできます。常にランタイムステージで
RUN adduser --disabled-password appuser && USER appuserを追加します - 他のサービスが
depends_onするサービスにヘルスチェックがない —condition: service_healthyがないdepends_onは、依存関係が実際に準備できる前に依存サービスを即座に開始します。常にhealthcheckを定義してservice_healthyを使用します - 環境変数としてプレーンテキストのシークレット — 環境変数は
docker inspect、CI ログ、およびイメージレイヤーに表示される可能性があります。Docker シークレット、シークレット管理システム、またはホスト環境参照(SECRET_KEY: ${SECRET_KEY})経由で渡します .dockerignoreがない — これがないと、COPY . .はリポジト全体(.git、node_modules、__pycache__、.env)をビルドコンテキストに送り、イメージサイズを肥大化させ、シークレット漏洩の可能性があります- ビルドツールを本番にも含めるシングルステージビルド — コンパイラ、開発ヘッダー、テスト依存関係を実行時イメージに含めると、攻撃対象範囲とイメージサイズが増加します。マルチステージビルドを使用して、実行時ステージが slim ベースから新しく始まるようにします
- データ永続化のための匿名ボリューム —
volumes: ["/var/lib/postgresql/data"](名前付きボリュームなし)はdocker compose downで再作成されます。pg_data:/var/lib/postgresql/dataのような名前付きボリュームを使用して、再起動後もデータを保持します
チェックリスト
- マルチステージビルドを使用 — builder がインストール、runtime に必要なもののみ
-
.dockerignoreが.git、node_modules、.env、__pycache__を除外 - ソースコード前に依存関係をコピー(レイヤーキャッシュ)
- 実行時ステージで非 root ユーザーを使用
- 他のサービスが
depends_onするサービスにヘルスチェックを定義 -
depends_onがservice_startedではなくcondition: service_healthyを使用 - Dockerfile に硬く書かれたシークレットや提交済み
.envがない - ボリュームが名前付き(匿名ではなく)で永続化したいデータ向け
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- kid-sid
- ライセンス
- MIT
- 最終更新
- 2026/5/11
Source: https://github.com/kid-sid/claude-spellbook / ライセンス: MIT