メインコンテンツまでスキップ

第13章:サービス間通信(Composeネットワーク)を理解する🕸️📡

この章でやることはシンプルです👇 「コンテナ同士は “サービス名” でつながる」 を体に入れます💪✨


1) まずは超ざっくり結論🎯

  • Composeは、起動すると デフォルトのネットワークを1つ作って そこに全サービスを参加させます。 そして各サービスは サービス名(例: db)で名前解決できる ようになります。(Docker Documentation)
  • サービス間通信で使うのは CONTAINER_PORT(コンテナ側ポート) です。 HOST_PORT(ホスト側ポート) は “外から入るため” のもの。(Docker Documentation)

つまり: ✅ API→DB は db:5432 ✅ API→Redis は redis:6379 ✅ 自分のPC→API は localhost:xxxx(公開してるときだけ) って感じです😊


2) なぜ「サービス名」でつながるの?🧠🔍

Composeのネットワークでは、

  • services: に書いた キー(サービス名)
  • DNS名(ホスト名)として使える

という設計になってます。(Docker Documentation)

たとえば services: db: があれば、同じネットワークの他サービスからは db で到達可能 です👍


3) ここが一番ハマる:localhost の罠🪤😇

コンテナの中で localhost と書いたら、それは…

「そのコンテナ自身」 です😵‍💫

だからAPIコンテナからDBに繋ぐのに localhost:5432 と書くと、 “APIコンテナの中の5432” を探しにいってコケます💥

✅ 正しくは db:5432(サービス名+コンテナ側ポート)です。(Docker Documentation)


4) いったん最小構成で手を動かす✋🐳

4-1) compose.yaml(通信の要点だけ)📄✨

ポイント:

  • APIだけ外に出したいから ports:
  • DB/Redisは “中だけ” なら expose: でOK(=ホストには出さない)(Docker Documentation)
services:
api:
build: ./api
ports:
- "3000:3000"
environment:
# ✅ “db” はサービス名
DATABASE_URL: "postgres://app:app@db:5432/appdb"
# ✅ “redis” もサービス名
REDIS_URL: "redis://redis:6379"
depends_on:
- db
- redis

db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: appdb
expose:
- "5432"

redis:
image: redis:7
expose:
- "6379"

💡 ports: は「ホスト↔コンテナのポートマッピング」です。(Docker Documentation) 💡 expose: は「ネットワーク内で見える入口(ただしホストには公開しない)」です。(Docker Documentation)


4-2) API側(TypeScript)で “ホスト名は db” を使う🧩🧑‍💻

// api/src/db.ts
import pg from "pg";

const { Client } = pg;

export async function connectDb() {
const url = process.env.DATABASE_URL!;
const client = new Client({ connectionString: url });
await client.connect();
const r = await client.query("select now() as now");
await client.end();
return r.rows[0].now;
}

db ってどこ?」は、ComposeネットワークのDNSが解決してくれます。(Docker Documentation)


5) “見える化” 実験:DNSで引けてるか確認する🔎🧪

5-1) 起動

docker compose up -d
docker compose ps

5-2) APIコンテナ内から db の名前解決を試す(NodeでOK)🧠✨

docker compose exec api node -e "require('dns').lookup('db', console.log)"
docker compose exec api node -e "require('dns').lookup('redis', console.log)"

IPが返ってくれば サービス名→IP が動いてます🎉 (IPは変わることがあるけど、名前 db は変わらない のが大事!)(Docker Documentation)


6) HOST_PORT と CONTAINER_PORT を一撃で整理🧷📌

例:もしDBをこう公開したら…

db:
ports:
- "8001:5432"
  • コンテナ同士(API→DB)db:5432(CONTAINER_PORT)(Docker Documentation)
  • 自分のPC→DBlocalhost:8001(HOST_PORT)

この “二重ポート” が混乱ポイントです😂


7) ちょい実戦:ネットワークを分けて「見せたくない」を作る🛡️🧱

「APIは外に見せるけど、DBは裏側だけ」ってやりたいとき、 ネットワークを front / back に分けると気持ちよく整理できます😎

Composeは複数ネットワークを定義して、サービスごとに参加ネットワークを指定できます。(Docker Documentation)

services:
api:
build: ./api
ports:
- "3000:3000"
networks: [front, back]

db:
image: postgres:18
networks: [back]

networks:
front: {}
back: {}

これでDBは front側から見えない(=分離)になります🧼✨


8) トラブルシュート集(ここだけ見れば勝てる)🧯😺

A) getaddrinfo ENOTFOUND db(dbが見つからん)

ありがち原因👇

  • サービス名が違う(db じゃなくて postgres だった、とか)
  • 同じComposeプロジェクト/同じネットワークにいない(ネットワーク分けたのに apiback に入ってない等)(Docker Documentation)

B) ECONNREFUSED db:5432(見つかるけど拒否)

  • DBコンテナが起動直後でまだ準備できてない(次章の “待ち合わせ” で解決が王道です⏳🩺)

C) 「PCからDBに繋がらない」

  • ports: を書いてない(=外には出てない)
  • あるいは公開してても、ホスト側は HOST_PORT を使う必要がある(例:localhost:8001)(Docker Documentation)

D) セキュリティ的に「公開したくない…」😱

ポート公開は “外にも開く” ので注意です⚠️ 必要なときだけ 127.0.0.1 バインドにするのが安全寄りです。(Docker Documentation)

例:

ports:
- "127.0.0.1:8001:5432"

9) AIに頼るときの「良い聞き方」🤖🧠

コピペ用プロンプト👇(短くて効きます✨)

  • 「Composeで api から db (Postgres) に繋ぐ。サービス名で接続する前提で DATABASE_URL を作って」
  • portsexpose の使い分けを、ホスト接続とサービス間通信の観点で説明して。設定例も出して」

10) この章のまとめ✅🎉

  • Composeは デフォルトネットワーク を作り、サービスは 名前で発見できる(Docker Documentation)
  • サービス間通信は サービス名 + CONTAINER_PORT(例:db:5432)(Docker Documentation)
  • 外から入るのは ports、内だけなら expose がスッキリ(Docker Documentation)
  • localhost の意味が “場所によって変わる” のが最大の罠🪤😇

次の第14章(待ち合わせ:healthcheck / depends_on)に入ると、 「DBが起きる前にAPIが落ちる😵」がかなり減って、体験が一段よくなりますよ〜⏳🩺✨