Docker
Docker Compose에서 컨테이너 이름에 의존하지 않기
Docker Compose로 여러 컨테이너를 관리할 때, 이름 대신 서비스 이름으로 통신하는 방법을 정리했다.
Docker Compose를 사용할 때, 컨테이너 간에 통신할 때 컨테이너의 실제 이름(예: my-app-db-1)에 의존하면 문제가 생긴다. 컨테이너는 재시작될 때마다 이름이 바뀔 수 있기 때문이다.
대신, docker-compose.yml에서 정의한 서비스 이름(예: db)을 호스트명으로 사용해야 한다.
문제: 컨테이너 이름에 의존
version: '3'
services:
app:
image: myapp:latest
environment:
DATABASE_URL: "postgresql://user:pass@my-app-db-1:5432/mydb"
db:
image: postgres:15
container_name: my-app-db-1 # 실제 컨테이너 이름
이렇게 하면, 컨테이너를 다시 만들 때마다 이름이 my-app-db-2, my-app-db-3 식으로 변경되고, 환경변수는 구식 이름을 가리키게 된다.
해결: 서비스 이름 사용
version: '3.8'
services:
app:
build: .
environment:
DATABASE_URL: "postgresql://user:pass@db:5432/mydb"
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
중요한 포인트:
- 서비스 이름은
db app서비스에서db로 접속할 때 호스트명은db사용container_name은 지정하지 않음 (또는 지정해도 상관없지만 의존하지 않음)
Docker Compose 네트워크
Docker Compose는 자동으로 서비스들 간 네트워크를 만든다. 같은 Compose 프로젝트의 서비스들은 서비스 이름으로 서로를 찾을 수 있다.
# 컨테이너 내부에서 다른 서비스에 접속
docker-compose exec app ping db
# PING db (172.20.0.2)
Node.js 애플리케이션 예시
// config/database.js
const sequelize = new Sequelize({
host: process.env.DB_HOST || 'db', // 'db'가 기본값 (서비스 이름)
port: 5432,
username: 'user',
password: 'pass',
database: 'mydb',
});
환경변수에서 오버라이드하지 않으면, 자동으로 서비스 이름 db를 사용한다.
depends_on 사용
version: '3.8'
services:
app:
build: .
depends_on:
db:
condition: service_healthy
db:
image: postgres:15
healthcheck:
test: ["CMD", "pg_isready", "-U", "user"]
interval: 10s
timeout: 5s
retries: 5
depends_on은 db 서비스가 시작되고 healthy 상태가 될 때까지 app의 시작을 지연시킨다.
여러 네트워크를 사용하는 경우
version: '3.8'
services:
web:
build: .
networks:
- frontend
- backend
db:
image: postgres:15
networks:
- backend
cache:
image: redis:7
networks:
- frontend
- backend
networks:
frontend:
backend:
같은 네트워크에 속한 서비스들만 서로 통신할 수 있다. web은 db에는 접근 가능하지만, cache로는 web → cache → db 경로로 통신한다.
실수하기 쉬운 부분
-
localhost 사용:
DATABASE_URL: localhost:5432- 이건 컨테이너 내부에서 작동 안 함- 올바른 방법:
DATABASE_URL: db:5432
- 올바른 방법:
-
컨테이너 이름 직접 사용:
container_name: specific-name으로 고정하면, 확장성이 떨어짐- 올바른 방법:
container_name생략하고 서비스 이름 사용
- 올바른 방법:
-
외부에서 컨테이너 접속: 컨테이너 내부에서는 서비스 이름, 외부에서는 localhost 사용
# 컨테이너 내부
docker-compose exec app psql -h db -U user mydb
# 호스트에서
psql -h localhost -p 5432 -U user mydb
테스트하기
# 컨테이너가 제대로 통신하는지 확인
docker-compose up -d
# 앱 컨테이너에서 db 서비스에 ping
docker-compose exec app ping db
# 또는 curl로 다른 서비스 접속 테스트
docker-compose exec web curl http://api:3000/health
프로덕션 배포
Docker Compose는 개발 환경에서 주로 사용된다. 프로덕션에서는 Kubernetes나 Docker Swarm 같은 오케스트레이션 도구를 사용하면, 비슷한 서비스 디스커버리 기능을 제공한다.
최종 체크리스트
- 환경변수에 컨테이너 실제 이름을 하드코딩했는가? (제거)
- 서비스 이름으로 통신하는가?
depends_on으로 서비스 시작 순서를 명시했는가?- 네트워크 설정이 필요한가? (여러 네트워크 사용 시)
- 로컬 테스트에서 통신이 제대로 되는가?
Docker Compose의 서비스 디스커버리를 제대로 이해하면, 컨테이너를 재시작해도 안정적으로 통신할 수 있다.