Docker 開発環境 コピペで使える Tips 集 — compose・マルチステージビルド・Devcontainer

Docker 開発環境のコピペで使えるTips集です。日々の実務で繰り返し使うパターンをまとめました。compose・マルチステージビルド・Devcontainer の順に紹介します。

docker-compose の定番パターン

DB + アプリ + ボリューム構成

Web アプリ開発で最もよく使う構成です。PostgreSQL とアプリサーバーをひとまとめにしています。

# compose.yaml
services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: devpassword
      POSTGRES_DB: devdb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U devuser -d devdb"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  app:
    build:
      context: .
      target: dev
    environment:
      DATABASE_URL: postgres://devuser:devpassword@db:5432/devdb
    volumes:
      - .:/app
      - node_modules:/app/node_modules
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy
    command: npm run dev

volumes:
  postgres_data:
  node_modules:

Redis を追加する場合

services:
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

depends_on でアプリが Redis のヘルスチェック通過後に起動するよう制御できます。

環境変数ファイルの分離

services:
  app:
    env_file:
      - .env
      - .env.local

.env はデフォルト値のみ(リポジトリにコミット可)、.env.local.gitignore に入れて秘密情報を分離する運用が定番です。

マルチステージビルドで本番イメージを軽量化

開発用ツールを含まない軽量な本番イメージを作るパターンです。Node.js アプリを例に示します。

# Dockerfile

# --- base ---
FROM node:22-alpine AS base
WORKDIR /app
COPY package*.json ./

# --- dev ---
FROM base AS dev
RUN npm ci
COPY . .
CMD ["npm", "run", "dev"]

# --- builder ---
FROM base AS builder
RUN npm ci --omit=dev
COPY . .
RUN npm run build

# --- prod ---
FROM node:22-alpine AS prod
WORKDIR /app
ENV NODE_ENV=production

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./

RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 3000
CMD ["node", "dist/index.js"]

compose.yamltarget でステージを切り替えます。

services:
  app:
    build:
      context: .
      target: dev   # 本番は prod に変更

Python(FastAPI)の場合:

FROM python:3.12-slim AS base
WORKDIR /app
COPY requirements*.txt ./

FROM base AS dev
RUN pip install -r requirements-dev.txt
COPY . .
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]

FROM base AS prod
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN adduser --disabled-password --no-create-home appuser
USER appuser
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

ヘルスチェック設定

Dockerfile 内に記述する場合

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

compose.yaml に記述する場合(上書き可能で柔軟)

services:
  app:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      start_period: 15s
      retries: 3

start_period はアプリの起動時間に合わせて設定します。起動が遅いサービスはここを長くしないと depends_on: condition: service_healthy で永遠に待ち続けます。

ヘルスチェック状態の確認:

docker inspect --format='{{json .State.Health}}' <container_name> | jq

.dockerignore の書き方

ビルドコンテキストが大きいほどビルドが遅くなります。.dockerignore で不要なものを除外します。

# .dockerignore

# 依存パッケージ(コンテナ内でインストール)
node_modules
.venv
__pycache__
*.pyc
*.pyo

# ビルド成果物
dist
build
.next
out

# VCS
.git
.gitignore

# ローカル設定・秘密情報
.env
.env.*
!.env.example
*.local

# エディタ・OS
.DS_Store
Thumbs.db
.vscode
.idea

# テスト・CI
coverage
.nyc_output
*.test.ts
*.spec.ts

# ドキュメント
*.md
docs

確認コマンド:

# ビルドコンテキストのサイズを確認
docker build --no-cache . 2>&1 | head -5

# .dockerignore が効いているか確認(ファイルリスト出力)
docker build --no-cache -f - . <<'EOF'
FROM busybox
COPY . /ctx
RUN find /ctx | sort
EOF

よく使う docker コマンド集

起動・停止

# 起動(バックグラウンド)
docker compose up -d

# 特定サービスだけ再起動
docker compose restart app

# ログをリアルタイムで見る
docker compose logs -f app

# コンテナに入る
docker compose exec app sh

# 一時的にコマンドを実行(コンテナを新規作成して削除)
docker compose run --rm app npm run migrate

イメージ・コンテナの掃除

# 停止中コンテナをすべて削除
docker container prune -f

# タグなしイメージを削除
docker image prune -f

# 未使用ボリュームを削除(データが消えるので注意)
docker volume prune -f

# 未使用ネットワークを削除
docker network prune -f

# 上記すべてを一括(ビルドキャッシュも含む)
docker system prune -af --volumes

デバッグ

# コンテナのリソース使用量をリアルタイム表示
docker stats

# コンテナの詳細情報(IP・環境変数など)
docker inspect <container_name>

# イメージのレイヤー構成確認
docker history <image_name>

# ビルドキャッシュの確認
docker buildx du

イメージのビルド・タグ付け

# マルチステージのターゲットを指定してビルド
docker build --target prod -t myapp:latest .

# BuildKit を有効にしてビルド(デフォルト有効、キャッシュ効率が上がる)
DOCKER_BUILDKIT=1 docker build -t myapp:latest .

# ビルドキャッシュをレジストリに保存(CI で有効)
docker buildx build \
  --cache-from type=registry,ref=ghcr.io/myorg/myapp:cache \
  --cache-to   type=registry,ref=ghcr.io/myorg/myapp:cache,mode=max \
  -t ghcr.io/myorg/myapp:latest .

Devcontainer / Dev Containers の基本設定

VS Code や GitHub Codespaces で使える Dev Containers の設定例です。

ディレクトリ構成

.devcontainer/
├── devcontainer.json
└── compose.yaml        # 既存の compose.yaml を参照してもOK

Node.js プロジェクト

// .devcontainer/devcontainer.json
{
  "name": "Node.js Dev",
  "dockerComposeFile": "../compose.yaml",
  "service": "app",
  "workspaceFolder": "/app",

  "features": {
    "ghcr.io/devcontainers/features/git:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {}
  },

  "customizations": {
    "vscode": {
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "ms-vscode.vscode-typescript-next"
      ],
      "settings": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "esbenp.prettier-vscode"
      }
    }
  },

  "postCreateCommand": "npm ci",
  "remoteUser": "node"
}

Python プロジェクト

// .devcontainer/devcontainer.json
{
  "name": "Python Dev",
  "image": "mcr.microsoft.com/devcontainers/python:3.12",
  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",

  "features": {
    "ghcr.io/devcontainers/features/docker-in-docker:2": {}
  },

  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance",
        "charliermarsh.ruff"
      ],
      "settings": {
        "python.defaultInterpreterPath": "/usr/local/bin/python",
        "[python]": {
          "editor.defaultFormatter": "charliermarsh.ruff"
        }
      }
    }
  },

  "postCreateCommand": "pip install -r requirements-dev.txt",
  "remoteUser": "vscode"
}

compose.yaml と組み合わせる場合

既存の compose.yaml をそのまま参照できます。

{
  "name": "Full Stack Dev",
  "dockerComposeFile": ["../compose.yaml", "compose.override.yaml"],
  "service": "app",
  "workspaceFolder": "/app",
  "shutdownAction": "stopCompose"
}
# .devcontainer/compose.override.yaml
services:
  app:
    command: sleep infinity

command: sleep infinity でコンテナを起動したまま VS Code が制御を握る構成です。

まとめ

カテゴリポイント
compose 構成healthcheck + depends_on: condition: service_healthy でサービス起動順を制御
マルチステージビルドtarget で dev/prod を切り替え。本番イメージに開発ツールを含めない
ヘルスチェックstart_period を起動時間に合わせて設定。docker inspect でデバッグ
.dockerignorenode_modules / .git / .env は必ず除外。ビルドキャッシュ効率が大幅改善
掃除コマンドdocker system prune -af --volumes で一括クリア(ボリューム削除は要注意)
DevcontainerpostCreateCommand で依存インストールを自動化。compose と組み合わせて DB も起動