docker compose up은 됐는데, 한 서비스에서 다른 서비스로 요청하면 connection refused나 could not resolve host가 뜨는 경우입니다. Compose는 기본적으로 모든 서비스를 하나의 사용자 정의 네트워크에 묶고, 서비스명을 DNS 이름으로 등록합니다. 통신이 안 되면 거의 이 규칙을 잘못 쓰고 있는 것입니다.
1단계 — 에러 메시지부터 본다
docker compose logs <service>
# 안에서 직접 연결 시도
docker compose exec api ping db
docker compose exec api wget -qO- http://db:5432
could not resolve host인지 connection refused인지에 따라 원인이 갈립니다.
2단계 — 메시지로 원인 좁히기
| 증상 | 원인 |
|---|---|
could not resolve host: db | 서비스명 오타 또는 다른 네트워크에 있음 |
connection refused | 대상 서비스가 아직 안 떴거나 포트가 다름 |
localhost로 연결 실패 | 컨테이너 안 localhost는 자기 자신을 가리킴 |
| 외부에서만 안 됨 | ports 미설정(내부 통신엔 불필요) |
원인별 해결
① localhost로 다른 서비스를 부름 — 가장 흔한 실수. 컨테이너 안에서 localhost는 그 컨테이너 자신입니다. 다른 서비스는 서비스명으로 부릅니다.
# api 컨테이너의 DB 접속 주소
# 틀림: localhost:5432
# 맞음: db:5432 (db는 compose 서비스명)
services:
api:
environment:
DATABASE_URL: "postgres://user:pw@db:5432/app"
db:
image: postgres:16
② 호스트 포트와 컨테이너 포트 혼동 — ports: "8080:5432"의 왼쪽(8080)은 호스트 노출용입니다. 컨테이너끼리는 **컨테이너 내부 포트(5432)**로 직접 통신하므로, 서비스 간 통신에는 ports가 필요 없습니다. expose나 그냥 내부 포트를 씁니다.
③ 서로 다른 네트워크에 있음 — networks:를 수동 지정했는데 두 서비스가 다른 네트워크면 이름 해석이 안 됩니다. 같은 네트워크에 두거나 기본 네트워크를 그대로 씁니다.
docker compose exec api getent hosts db # 비어 있으면 같은 네트워크 아님
④ 대상 서비스가 아직 안 떴다 (connection refused) — depends_on은 컨테이너 시작 순서만 보장하지 "준비 완료"는 보장하지 않습니다. 헬스체크 기반 대기를 씁니다.
services:
db:
healthcheck:
test: ["CMD", "pg_isready", "-U", "user"]
interval: 5s
api:
depends_on:
db:
condition: service_healthy
체크리스트
docker compose ps # 대상 서비스가 Up인지
docker compose exec api getent hosts db # 서비스명 DNS 해석 여부
docker network inspect <proj>_default # 두 서비스가 같은 net에 있나
docker compose exec api wget -qO- http://db:<port> # 내부 포트로 직접 시도
이름 해석이 되는지, 같은 네트워크인지, 대상이 떴는지 — 이 셋이면 원인이 갈립니다.
Compose 네트워크와 서비스명 DNS를 직접 끊고 연결해보는 실습은 도커 트랙에서 회원가입 없이 무료로 할 수 있습니다.