プロジェクトが成長すると、docker-compose.yml は必ず肥大化します。
- Vueだけ触りたいのに全部起動する
- DBだけ再起動したい
- mock系が重い
- 起動順トラブルが増える
こうなったら compose分割のタイミング です。
この記事では単なる分割方法ではなく、
✔ 設計思想
✔ 実装例(compose & Makefile)
✔ メリット
✔ 今後の改善
まで整理します。
🎯 分割の目的
compose分割はマイクロサービス化ではありません。
目的は:
- 責務分離
- 起動単位最適化
- 開発体験向上
- CI/CD拡張の布石
- 将来のk8s移行準備
🧱 責務分離モデル
app → アプリ層
infra → 本番相当ミドルウェア
mock → 開発補助ツール
🌐 共通ネットワーク(重要)
分割する場合は external network を使います。
docker network create app-network
1️⃣ docker-compose.infra.yaml
version: "3.9"
services:
db:
image: mysql:8
container_name: app-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app
ports:
- "3306:3306"
volumes:
- db-data:/var/lib/mysql
networks:
- app-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 5
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
container_name: elasticsearch
restart: unless-stopped
environment:
discovery.type: single-node
xpack.security.enabled: "false"
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9200 || exit 1"]
interval: 10s
timeout: 5s
retries: 10
volumes:
db-data:
es-data:
networks:
app-network:
external: true
2️⃣ docker-compose.app.yaml
version: "3.9"
services:
laravel-api:
build: ./laravel-api
container_name: laravel-api
restart: unless-stopped
networks:
- app-network
command: >
sh -c "
until nc -z db 3306; do sleep 1; done;
until nc -z elasticsearch 9200; do sleep 1; done;
php-fpm
"
laravel-web:
build: ./laravel-web
container_name: laravel-web
restart: unless-stopped
ports:
- "8080:80"
networks:
- app-network
vue:
build: ./vue
container_name: vue
restart: unless-stopped
ports:
- "5173:5173"
networks:
- app-network
networks:
app-network:
external: true
3️⃣ docker-compose.mock.yaml
version: "3.9"
services:
moto:
image: motoserver/moto
container_name: moto
restart: unless-stopped
ports:
- "5000:5000"
networks:
- app-network
mailpit:
image: axllent/mailpit
container_name: mailpit
restart: unless-stopped
ports:
- "8025:8025"
- "1025:1025"
networks:
- app-network
firebase-emulator:
image: node:20
container_name: firebase-emulator
working_dir: /app
volumes:
- ./firebase:/app
command: >
sh -c "
npm install -g firebase-tools &&
firebase emulators:start --host 0.0.0.0
"
ports:
- "4000:4000"
- "8080:8080"
- "9099:9099"
networks:
- app-network
networks:
app-network:
external: true
🛠 Makefile(運用標準化)
NETWORK=app-network
INFRA=docker-compose.infra.yaml
APP=docker-compose.app.yaml
MOCK=docker-compose.mock.yaml
.PHONY: network infra-up infra-down app-up app-down mock-up mock-down all-up all-down vue logs ps
network:
docker network inspect $(NETWORK) >/dev/null 2>&1 || docker network create $(NETWORK)
infra-up: network
docker compose -f $(INFRA) up -d
infra-down:
docker compose -f $(INFRA) down
app-up:
docker compose -f $(APP) up -d
app-down:
docker compose -f $(APP) down
mock-up:
docker compose -f $(MOCK) up -d
mock-down:
docker compose -f $(MOCK) down
all-up: infra-up app-up mock-up
all-down:
docker compose -f $(APP) down
docker compose -f $(MOCK) down
docker compose -f $(INFRA) down
vue:
docker compose -f $(APP) up vue
logs:
docker compose -f $(APP) logs -f
ps:
docker compose -f $(APP) ps
🚀 運用例
全起動:
make all-up
Vueのみ:
make vue
infraのみ:
make infra-up
停止:
make all-down
🎯 実務メリット
① 起動時間短縮
Vueだけ起動可能 → 開発速度向上
② 障害切り分け容易
infra再起動してもappは触らない
③ CI/CD拡張性
- integration専用compose
- test専用compose
- e2e専用compose
へ拡張可能
④ 本番移行が容易
infra層を:
- RDS
- OpenSearch
- Firebase本番
へ置き換えるだけ
⑤ k8s移行が自然
この分割は:
- Deployment
- StatefulSet
- Service
へそのまま対応可能
⚠ 注意点
- depends_onは跨げない
- wait処理が必要
- external network必須
- ドキュメント必須
🔮 今後の改善
✔ profile活用
✔ override導入
✔ テスト専用compose
✔ CI高速化
✔ k8s移行
🧠 設計の成熟度
| フェーズ | 状態 |
|---|---|
| 初期 | 1 compose |
| 中期 | app/infra分割 |
| 成長 | mock分離 + Makefile |
| 大規模 | k8s |
今の構成は:
中規模〜成長フェーズの健全な設計
✨ まとめ
正直、最初は1ファイルで十分でした。
でもサービスが増えてくると、修正のたびに全部起動するのが地味にストレスでした。
分割してみると
- 必要なものだけ立ち上げられる
- どこが壊れているか分かりやすい
- 将来の構成変更にも対応しやすい
と、想像以上にメリットがありました。
同じようにcomposeが重くなってきた人の参考になれば嬉しいです。