# [Docker Compose 개념] 네트워크와 볼륨이 상태를 만드는 방식
- 네트워크와 볼륨이 상태를 만드는 방식 ← 현재 문서
컨테이너는 쉽게 만들고 쉽게 지우도록 설계되어 있다. 이 특성은 배포와 재현성에는 좋지만, 서버 애플리케이션에는 두 가지 질문을 남긴다.
첫째, 컨테이너끼리는 어떻게 서로를 찾는가. 둘째, 컨테이너를 지워도 남아야 하는 데이터는 어디에 두는가. Docker Compose에서는 이 두 질문에 각각 네트워크와 볼륨으로 답한다.
같은 Compose 프로젝트의 서비스는 이름으로 통신한다
현재 예시 앱은 PostgreSQL에 접속해야 한다. 호스트에서 앱을 실행할 때는 DB 주소가 보통 localhost:5432일 수 있다. 하지만 앱을 컨테이너 안에서 실행하면 상황이 달라진다.
컨테이너 안의 localhost는 호스트가 아니라 그 컨테이너 자신이다. 앱 컨테이너 내부에서 localhost:5432를 찾으면 DB 컨테이너가 아니라 앱 컨테이너 내부의 5432 포트를 찾게 된다.
Compose 네트워크에서는 서비스 이름이 DNS 이름이 된다. 따라서 앱 컨테이너에서 DB 컨테이너로 접속할 때는 다음 주소를 써야 한다.
jdbc:postgresql://db:5432/discodeit
여기서 db는 Compose의 서비스 이름이다.
services:
db:
image: postgres:15-alpine
서비스 이름을 바꾸면 DB URL도 함께 바꿔야 한다. 예를 들어 서비스를 postgres로 바꾸면 URL은 jdbc:postgresql://postgres:5432/...가 된다.
ports는 외부 진입점이고 네트워크는 내부 경로다
ports는 호스트에서 컨테이너로 들어오는 문이다.
app:
ports:
- "8081:80"
이 설정이 있으면 브라우저에서 http://localhost:8081로 앱에 접근할 수 있다. 하지만 앱이 DB에 접근하는 데 이 포트 매핑이 필요한 것은 아니다. 앱과 DB는 Compose의 default network 안에서 직접 통신한다.
두 경로를 분리해서 생각해야 한다.
| 경로 | 예시 | 필요한 설정 |
|---|---|---|
| 호스트 → 앱 컨테이너 | localhost:8081 → app:80 | app.ports |
| 호스트 → DB 컨테이너 | localhost:5432 → db:5432 | db.ports |
| 앱 컨테이너 → DB 컨테이너 | app → db:5432 | 같은 Compose 네트워크 |
DB의 ports를 제거해도 앱 컨테이너는 db:5432로 계속 접속할 수 있다. 반대로 DB의 ports를 열어도 앱의 DB URL이 localhost이면 컨테이너 내부에서는 실패할 수 있다.
named volume은 컨테이너 밖에 데이터를 남긴다
PostgreSQL은 데이터를 /var/lib/postgresql/data에 저장한다. 이 경로가 컨테이너 내부 파일시스템에만 있으면 컨테이너 삭제 시 데이터도 사라진다. 그래서 현재 Compose 파일은 named volume을 붙인다.
db:
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
이 설정은 postgres_data라는 Docker 볼륨을 만들고, 그 볼륨을 DB 컨테이너의 데이터 디렉터리에 연결한다. 컨테이너를 다시 만들어도 같은 볼륨을 붙이면 DB 데이터가 유지된다.
앱도 파일 저장용 볼륨을 가진다.
app:
volumes:
- app_storage:/app/storage
volumes:
app_storage:
현재 운영 프로필은 discodeit.storage.type: s3를 사용하므로 실제 파일 저장이 S3로 갈 수 있다. 그래도 로컬 저장 방식으로 바꾸거나 일부 파일을 컨테이너 내부에 보관하는 경우를 생각하면 앱 저장소 볼륨은 의미가 있다.
schema.sql은 매번 실행되지 않는다
현재 DB 서비스는 schema.sql을 PostgreSQL 초기화 디렉터리에 읽기 전용으로 마운트한다.
db:
volumes:
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
PostgreSQL 공식 이미지는 데이터 디렉터리가 비어 있을 때 /docker-entrypoint-initdb.d 아래의 초기화 파일을 실행한다. 중요한 점은 볼륨이 이미 초기화되어 있으면 다시 실행되지 않는다는 것이다.
따라서 schema.sql을 수정한 뒤 docker compose up만 다시 해도 기존 DB에는 반영되지 않을 수 있다. 초기 스키마를 다시 적용하려면 다음 중 하나를 선택해야 한다.
- 마이그레이션 도구로 변경분을 적용한다.
- 직접 SQL을 실행한다.
- 개발용 데이터라면 볼륨을 삭제하고 새로 초기화한다.
볼륨 삭제는 데이터 삭제다. 실습할 때만 의도적으로 실행해야 한다.
docker compose down -v
docker compose down은 컨테이너와 네트워크를 정리한다. -v를 붙이면 Compose가 만든 named volume까지 삭제한다. PostgreSQL 데이터도 같이 사라진다.
네트워크와 볼륨을 같이 보면 실행 환경이 보인다
localhost:8081"] subgraph Network["Compose default network"] App["app
Spring Boot :80"] Db["db
PostgreSQL :5432"] end PgVol[("postgres_data
DB files")] AppVol[("app_storage
uploaded files")] Browser -->|"ports 8081:80"| App App -->|"db:5432"| Db Db --- PgVol App --- AppVol
이 그림에서 네트워크는 요청의 이동 경로이고, 볼륨은 데이터의 생존 위치다. 컨테이너를 지워도 볼륨은 남을 수 있고, 호스트 포트를 닫아도 내부 네트워크 통신은 유지될 수 있다.
참고한 공식 문서
- Docker Compose application model
- Define and manage volumes in Docker Compose
- Compose services reference