ローカル開発のためのDockerCompose:完全なセットアップガイド

Table of Contents
最新のウェブアプリケーションが単一のサービスで構成されることは稀です。典型的な2026年のスタックには、Node.jsまたはPythonのAPI、PostgreSQLデータベース、Redisキャッシュ、CeleryまたはBullMQワーカー、そしておそらくMinIOのようなローカルのS3互換ストレージが含まれます。これらの依存関係を手動で管理する — 特定のPostgresバージョンをインストールし、ポートを設定し、ターミナルタブをやりくりする — ことは、環境のずれ(environment drift)や、おなじみの「私のマシンでは動くのに」という問題を引き起こす原因となります。
Docker Composeは、ローカルインフラ全体を単一の宣言型YAMLファイルとして表現することで、この問題を解決します。2026年には、Docker Compose v2がDocker DesktopおよびDocker Engineに同梱され、BuildKitとネイティブに統合され、GPUプロファイル、ヘルスチェック、シークレットをサポートします。これにより、ローカルワークフローにおいて本番環境に対応できる能力を備えています。
Docker Compose to Kubernetes Converter
Generate Deployments, Services, ConfigMaps & Ingress
Convert multi-service Docker Compose v2/v3 YAML into production-grade Kubernetes manifests with custom replicas, health probes, resource limits, and PVC storage.
なぜdocker compose upが本番環境をミラーリングすべきなのか
目標は単なる利便性だけではありません。本番環境をミラーリングするComposeファイルは、ステージングに到達する前に環境固有のバグを捕捉します。強制すべき具体的なパリティポイントは以下の通りです。
- 同じPostgreSQLバージョン、同じエンコーディング(
UTF8)、同じロケール(en_US.UTF-8) - 同じRedisバージョンとエビクションポリシー(セッションキャッシュには
volatile-lru) - 同じ環境変数名(
.envから取得し、ハードコードしない) - 同じネットワークトポロジー(サービスは
localhostではなくサービス名で互いを検出する) - 同じユーザー権限(APIコンテナは非rootで実行され、K8sの
runAsNonRootをミラーリングする)
ステップ1: docker-compose.ymlファイル
以下は、Node.js APIとPostgreSQL、Redis、バックグラウンドワーカーのための、本番環境をミラーリングしたComposeファイルです。
# docker-compose.yml (Docker Compose v2 — no "version:" key needed)
name: myapp
services:
api:
build:
context: ./api
target: development
cache_from:
- type=local,src=/tmp/.buildx-cache
ports:
- "3000:3000"
volumes:
- ./api:/usr/src/app
- node_modules:/usr/src/app/node_modules # Prevent host node_modules leak
env_file:
- .env
environment:
NODE_ENV: development
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/myappdb
REDIS_URL: redis://redis:6379/0
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
command: npm run dev
user: "1001:1001" # Match your host UID to avoid root-owned volume files
worker:
build:
context: ./api
target: development
volumes:
- ./api:/usr/src/app
- node_modules:/usr/src/app/node_modules
env_file:
- .env
environment:
NODE_ENV: development
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/myappdb
REDIS_URL: redis://redis:6379/0
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
command: npm run worker
user: "1001:1001"
db:
image: postgres:16-alpine
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: myappdb
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=en_US.UTF-8"
volumes:
- pgdata:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/10-init.sql:ro
- ./db/seed.sql:/docker-entrypoint-initdb.d/20-seed.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d myappdb"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
redis:
image: redis:7-alpine
restart: unless-stopped
ports:
- "6379:6379"
command: >
redis-server
--maxmemory 256mb
--maxmemory-policy volatile-lru
--save ""
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
minio:
image: minio/minio:latest
ports:
- "9000:9000"
- "9001:9001" # MinIO Console UI
environment:
MINIO_ROOT_USER: ${MINIO_USER}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
command: server /data --console-address ":9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 3
volumes:
pgdata:
node_modules:
minio_data:
condition: service_healthyを使ったdepends_onが重要な理由
素朴なdepends_on: [db]は、コンテナが起動するのを待つだけで、PostgreSQLが接続を受け入れるのを待ちません。APIの最初のデータベースクエリは「接続拒否」となり、起動時にクラッシュします。適切なhealthcheckを持つcondition: service_healthyを使用することで、APIが起動する前にPostgresが実際に準備できていることを保証します。
node_modulesボリュームのトリック
node_modules:/usr/src/app/node_modulesという名前付きボリュームは、ホストのnode_modules(macOSまたはWindows用にコンパイルされたもの)がコンテナのLinux用にコンパイルされたバイナリを上書きするのを防ぎます。これがないと、bcryptやsharpのようなネイティブアドオンがコンテナ内で失敗します。
ステップ2: BuildKitキャッシュマウントを使用したマルチステージDockerfile
BuildKitキャッシュマウントは、npmキャッシュをビルド間で永続化することで、リビルドを劇的に高速化します。
# api/Dockerfile
FROM node:20-alpine AS base
WORKDIR /usr/src/app
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser
# Development stage — includes devDependencies, live reload
FROM base AS development
COPY package*.json ./
# BuildKit cache mount: npm cache persists across `docker compose build` runs
RUN --mount=type=cache,target=/root/.npm \
npm install
COPY . .
# CMD is overridden by docker-compose.yml
# Build stage — compiles TypeScript, runs tests
FROM base AS build
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
RUN npm run build && npm run test:ci
# Production runtime — minimal image, no devDependencies
FROM node:20-alpine AS production
WORKDIR /usr/src/app
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev
COPY --from=build /usr/src/app/dist ./dist
USER appuser
EXPOSE 3000
CMD ["node", "dist/main.js"]
--mount=type=cacheディレクティブはBuildKitの機能です。最初のビルドで依存関係がダウンロードされ、その後のビルドではキャッシュレイヤーから読み取られるため、ほとんどの反復的な変更でビルド時間が数分から数秒に短縮されます。
ステップ3: 環境シークレット管理
認証情報をバージョン管理にコミットしてはいけません。コミットされた.env.exampleとともに.envを使用してください。
# .env.example — committed to git
POSTGRES_PASSWORD=change_me_in_env
MINIO_USER=minioadmin
MINIO_PASSWORD=change_me_in_env
REPORTER_SECRET=change_me_in_env
# .env — gitignored, copied from .env.example
POSTGRES_PASSWORD=dev_local_secret_32chars
MINIO_USER=minioadmin
MINIO_PASSWORD=dev_local_minio_secret
REPORTER_SECRET=dev_reporter_secret
ローカルテストでの本番環境のようなシークレットには、Docker Compose Secretsがより安全な代替手段を提供します。これは、環境変数としてではなく、ファイルとしてシークレットをマウントします。
secrets:
db_password:
file: ./secrets/db_password.txt
services:
api:
secrets:
- db_password
environment:
DATABASE_PASSWORD_FILE: /run/secrets/db_password
ステップ4: 日常のワークフローコマンド
# Start the entire stack (foreground — see all logs)
docker compose up
# Start detached, tail only API logs
docker compose up -d && docker compose logs -f api
# Rebuild only the api image after Dockerfile changes
docker compose up --build api
# Run a one-off command inside the running api container
docker compose exec api npm run migrate:latest
# Run a new ephemeral container (doesn't affect the running api)
docker compose run --rm api npm run db:seed
# Stop containers, preserve volumes
docker compose down
# Nuclear reset: stop, remove containers, networks, AND volumes
docker compose down -v
# View resource usage
docker compose stats
ネットワークとサービスディスカバリ
Docker Composeは、name:の値がプレフィックスとして付加されたmyapp_defaultというプライベートネットワークを作成します。すべてのサービスはhttp://<service-name>:<internal-port>で到達可能です。
| アクセス元 | ターゲット | URL |
|---|---|---|
apiコンテナ | PostgreSQL | postgres://app:…@db:5432/myappdb |
apiコンテナ | Redis | redis://redis:6379/0 |
apiコンテナ | MinIO API | http://minio:9000 |
| あなたのブラウザ | API | http://localhost:3000 |
| あなたのブラウザ | MinIOコンソール | http://localhost:9001 |
ポートマッピング(ports:)は、コンテナのポートをホストマシンに公開します。マッピングがない場合、サービスは他のコンテナからは到達可能ですが、ブラウザからは到達できません。これは内部サービスを隔離するのに役立ちます。
オプションサービスのためのプロファイル
Jaegerトレースコレクターのようなオプションサービスは、必要なときにのみ起動するようにプロファイルを使用します。
services:
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
- "4317:4317"
profiles: ["observability"]
# Start with optional observability stack
docker compose --profile observability up
# Start without (default)
docker compose up
結論
適切に作成されたdocker-compose.ymlは、環境のずれをなくし、オンボーディング時間を数時間から数分に短縮し、CIパイプラインにすべての開発者のマシンと同じ決定論的な環境を提供します。投資はセットアップに1時間ですが、その見返りはチーム全体で数ヶ月分のデバッグ時間の節約になります。
こちらもおすすめです
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

Docker BuildKitのキャッシュマウントとマルチステージ最適化(2026年版ガイド)
Go、Node.js、Rustコンテナ向けに、BuildKitのキャッシュマウント、マルチステージターゲット、リモートのS3/レジストリキャッシュバックエンドを使用してDockerビルドを高速化します。
Read more
プラットフォームエンジニアリング: 開発者のためのGolden Pathを構築する
認知負荷を軽減し、CI/CDパイプラインを自動化し、プラットフォームエンジニアリングをスケールさせるInternal Developer Platform (IDP) とGolden Pathの構築方法を紹介します。
Read more
なぜ私のDockerイメージは1GBだったのか(そして50MBに縮小した方法)
マルチステージビルド、Alpineベース、distroless runtime、レイヤーキャッシュのベストプラクティスを活用して、Dockerコンテナイメージを1GBから50MBに削減する方法をご紹介します。
Read more