第23章:複数プロジェクトを同居させるためのネットワーク設計🧵🧠
この章は「AプロジェクトとBプロジェクトを同時に立ち上げても、ネットワーク周りで喧嘩しない🥊🚫」を作る回だよ〜! 結論から言うと、“入口(リバプロ)用の共有ネットワーク” を1本だけ外出し(external)して、各プロジェクトはそこに必要なサービスだけ参加させるのが、いちばん事故りにくいです💡✨ (Docker Documentation)
23.1 まずは「ネットワーク」を1枚の絵で理解する🖼️🐳
Dockerネットワークは超ざっくり言うと「コンテナ用のLAN(スイッチ)」です🔌 同じネットワークに繋いだコンテナ同士は、サービス名で通信できる(= 名前解決が効く)から、リバプロが楽になります😊 (Docker Documentation)
イメージ👇
internal(A):Aプロジェクトの中だけで完結するLANinternal(B):Bプロジェクトの中だけで完結するLANedge(shared):入口(リバプロ)と、外に見せたいサービスだけが繋がる共有LAN
(ブラウザ) 🧑💻🌐
|
localhost:80/443
|
[ Reverse Proxy ] 🚪✨
|
edge(shared) 🧵 ← 共有ネットワーク(external)
/ \
(Aのweb/api) (Bのweb/api)
| |
internal(A) internal(B)
/ | \ / | \
db redis etc db redis etc
(外から触らせない) (外から触らせない)
23.2 「何が喧嘩の原因?」を先に潰す😵💫🧯
複数プロジェクト同居でよくある地雷はこの3つ💣
- ネットワーク名が衝突する
- Composeはデフォルトでプロジェクトごとにネットワークを作るけど、その名前は “プロジェクト名” に依存します📛
- プロジェクト名はディレクトリ名ベースだったり、
-p/COMPOSE_PROJECT_NAME/ さらにトップレベルname:でも変えられます🧩 (Docker Documentation)
- externalにするべき共有ネットワークを、各プロジェクトが作ろうとして揉める
- 「共有したいのに、それぞれ別物を作ってる」状態になりがち😇
- 共有したいネットワークは
external: trueを使って “既存のネットワークに参加” させるのが安全です✅ (docs.docker.jp)
- 何でもかんでも共有ネットワークに繋いで、境界が消える
- DBやRedisまで
edge(shared)に繋ぐと「別プロジェクトから触れちゃう」事故が起きます🥶 - 共有は 入口に必要なサービスだけ に絞るのが鉄則👍✨
23.3 ベストプラクティス:共有ネットワークは「1本だけ」外出しする🧵🚪
ここから実践! やることはシンプルで、こう👇
- 共有ネットワーク(例:
dev-edge)を 先に作る - リバプロ側はそのネットワークに繋ぐ
- 各プロジェクトは “公開したいサービスだけ” をそのネットワークに繋ぐ
- プロジェクト内部は
internalで閉じる
ポイント:Composeの networks: には name: があって、これを使うと「プロジェクト名でスコープされない固定名」にできます📌
しかも external と一緒に使うのが定番!✨ (Docker Documentation)
23.4 ハンズオン:共有ネットワーク dev-edge を作って、A/Bを同居させる🛠️🎮
STEP0:共有ネットワークを作る(最初に1回だけ)🧵✨
PowerShell(またはVS Codeのターミナル)でOK!
docker network create dev-edge
docker network ls
dev-edge が見えたら成功🎉
✅
external: trueを使う場合、このネットワークが存在しないと Compose はエラーになります(「既存のやつ探して繋ぐ」動作だから) (docs.docker.jp)
STEP1:入口(proxy)スタックの compose.yaml 🧯🚪
例として、ここでは “proxy専用プロジェクト” を想定(第22章の続きのノリ)📦 大事なのは networks の書き方だけだから、リバプロはTraefikでもCaddyでもOKだよ👍
proxy/compose.yaml(例)
name: proxy
services:
proxy:
image: traefik:v3.6
command:
- --api.dashboard=true
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- edge
networks:
edge:
name: dev-edge
external: true
name: proxyは “プロジェクト名” を明示するためのやつ(複数同居で効く)🧷 (Docker Documentation)networks.edge.name: dev-edgeは 固定名(プロジェクト名で変化しない)📌 (Docker Documentation)external: trueで 既存 dev-edge を使う🧵 (docs.docker.jp)
起動:
cd proxy
docker compose up -d
STEP2:プロジェクトAの compose.yaml(internal + edge)🅰️🧩
project-a/compose.yaml(例:front + api + db)
name: project-a
services:
front:
image: node:24
working_dir: /app
volumes:
- ./:/app
command: bash -lc "npm ci && npm run dev -- --host 0.0.0.0 --port 5173"
networks:
- internal
- edge
labels:
- traefik.enable=true
- traefik.http.routers.a-front.rule=Host(`a.localhost`)
- traefik.http.services.a-front.loadbalancer.server.port=5173
api:
image: node:24
working_dir: /app
volumes:
- ./api:/app
command: bash -lc "npm ci && npm run dev -- --host 0.0.0.0 --port 3000"
networks:
- internal
- edge
labels:
- traefik.enable=true
- traefik.http.routers.a-api.rule=Host(`api-a.localhost`)
- traefik.http.services.a-api.loadbalancer.server.port=3000
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: postgres
networks:
- internal
networks:
internal: {}
edge:
name: dev-edge
external: true
ここでの設計意図💡
dbは internalだけ(外から見せない)🧊front/apiは internal + edge(内部連携もしつつ、入口にも出す)🚪✨- “同じネットワーク上だとサービス名で見つけられる” のがComposeの基本感覚です👍 (Docker Documentation)
起動:
cd project-a
docker compose up -d
STEP3:プロジェクトBも同じ作法で🅱️🌈
project-b/compose.yaml も同様に internal と edge(external) を持たせて、公開したいサービスだけ edge に参加させます✨
(ホスト名は b.localhost とかに変えるだけ!)
23.5 動作チェック:今、誰が dev-edge に繋がってる?🕵️♂️🔍
「ほんとに共有できてる?」を確認しよう!
docker network inspect dev-edge
Containers のところに
- proxyの
proxy - Aの
front/api - Bの
front/api
みたいに並んでたら勝ちです🏆✨
23.6 よくあるミス集(ここ超大事)📕🧯
ミス1:external: true を書いたのにネットワークが無い😇
症状:network dev-edge declared as external, but could not be found 的なエラー
対処:先に作る!
docker network create dev-edge
(これは仕様どおりだよ〜) (docs.docker.jp)
ミス2:name: dev-edge を書かず、プロジェクトごとに別ネットワークになってた😵💫
症状:Aとproxyが同じ “edge” って書いてるのに通信できない
原因:内部的には project-a_edge と proxy_edge みたいに別物になってるパターン
対処:共有したい方は name: で固定名 にする📌 (Docker Documentation)
ミス3:DBまで edge に繋いでしまった🥶
症状:BからAのDBに繋げられちゃう(やろうと思えば)
対処:db は internalだけ に戻す🍵✨
ミス4:プロジェクト名が意図せず変わって、ネットワーク名やボリューム名がブレる📛
原因:ディレクトリ名ベースでスコープされるから、場所を変えると変わることがある
対処:トップレベル name: / -p / COMPOSE_PROJECT_NAME を使って安定化🧷 (Docker Documentation)
23.7 ミニ課題🎯🧪(手を動かすと一気に定着する)
課題A:A/B/Cを同居させてみよう🧩🧩🧩
dev-edgeに参加するのはfrontだけにして、apiは internal のみにする- その代わり
front→apiは internal上でサービス名(例:http://api:3000)で叩く
狙い:公開境界を “最小” にする感覚 を作る✨
課題B:2つの “入口” を作ってみよう🚪🚪(上級の入口)
dev-edge-aとdev-edge-bを作る- proxyを2つ立てるか、entrypointを分けるか、好きな方で
狙い:チーム開発や複数案件の現場っぽい分離 を体験🔥
23.8 AIに聞くと爆速になる「質問テンプレ」🤖⚡
コピペで使ってOK!
- 「ComposeでA/Bプロジェクトを同居させたい。共有external network
dev-edgeを使う構成で、dbはinternalのみにして、Traefikラベルも含めたcompose.yamlを作って」 - 「
docker network inspect dev-edgeの結果を貼るから、どこが繋がってないか 推理して」 - 「
name:/COMPOSE_PROJECT_NAME/-pの優先順位を、今回の構成に当てはめて説明して」 (Docker Documentation)
23.9 章末チェックリスト✅✨
- 共有ネットワーク
dev-edgeを先に作った🧵 - proxy は
dev-edge (external)に繋がってる🚪 - 各プロジェクトは
internalを持ってる🏠 -
edgeに繋ぐのは “公開したいサービスだけ” に絞った🧊 -
name:でネットワーク名が固定されてる📌 (Docker Documentation)
次の章(第24章)は、この設計と相性抜群の 「ポート競合を永久に起こさないコツ📛🔒」 に行けるよ〜! 今の構成ができてると、24章がめちゃ気持ちよく進みます😄🚀