0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Docker Composeを責務で分割する実践設計

0
Posted at

プロジェクトが成長すると、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が重くなってきた人の参考になれば嬉しいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?