Docker Composeで開発環境を構築する実践ガイド

Docker Composeを使ってWebアプリの開発環境(Nginx + App + DB)を構築する手順を、実際のdocker-compose.ymlを交えて解説します。

Docker Composeとは

Docker Composeは複数のコンテナをまとめて定義・起動するためのツールです。docker-compose.yml に構成を書いておけば、docker compose up の一発で全コンテナが立ち上がります。

本記事では Nginx(リバースプロキシ)+ Go アプリ + PostgreSQL という典型的な3層構成を例に進めます。


ディレクトリ構成

project/
├── docker-compose.yml
├── nginx/
│   └── default.conf
├── app/
│   ├── Dockerfile
│   └── main.go
└── db/
    └── init.sql

docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: "3.9"

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 5s
      timeout: 5s
      retries: 5

  app:
    build: ./app
    environment:
      DATABASE_URL: postgres://appuser:secret@db:5432/appdb?sslmode=disable
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:8080"

  nginx:
    image: nginx:1.25-alpine
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    ports:
      - "80:80"
    depends_on:
      - app

volumes:
  db_data:

depends_oncondition: service_healthy を使うことで、PostgreSQLが起動してから(pg_isready が通ってから)アプリを起動できます。これがないと、DB接続前にアプリが先に起動してしまい、起動時のマイグレーションが失敗するケースがあります。


Nginxの設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
server {
    listen 80;

    location / {
        proxy_pass         http://app:8080;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Compose内のサービスはサービス名でDNS解決できるため、http://app:8080 という指定で通信できます。


アプリのDockerfile

マルチステージビルドでイメージサイズを小さくします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# ビルドステージ
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server .

# 実行ステージ
FROM alpine:3.19
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]

CGO_ENABLED=0 でCGOを無効にすることで、alpineの最小イメージで動かせる静的バイナリを生成します。


よく使うコマンド

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 起動(-d でバックグラウンド)
docker compose up -d

# ログ確認(サービス名省略で全コンテナ)
docker compose logs -f app

# コンテナに入る
docker compose exec app sh
docker compose exec db psql -U appuser -d appdb

# 停止(コンテナとネットワークを削除)
docker compose down

# ボリュームも含めて全削除
docker compose down -v

# 特定サービスだけ再ビルド
docker compose build app
docker compose up -d --no-deps app

本番環境との使い分け

開発環境では volumes でソースコードをマウントしてホットリロードを使いたいことが多いです。docker-compose.override.yml を使うと、開発時だけ追加設定を重ねられます。

1
2
3
4
5
6
# docker-compose.override.yml(開発時のみ自動読み込み)
services:
  app:
    volumes:
      - ./app:/app
    command: air   # ホットリロードツール

本番では docker-compose.prod.yml を別途用意し、-f で明示的に指定します。

1
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

まとめ

Docker Composeを使えばチームメンバー全員が同じ環境を再現できるため、「自分のマシンでは動く」問題を大幅に減らせます。