# [Docker Compose 실습] PostgreSQL 볼륨과 초기화 다루기

Docker Compose 실습편

- 현재 docker-compose.yml 진단하기

- Compose 파일 1차 정리하기

- Spring Boot 컨테이너 설정 맞추기

- PostgreSQL 볼륨과 초기화 다루기 ← 현재 문서

- 실행 검증과 문제 해결 루틴

DB 컨테이너에서 가장 중요한 것은 데이터가 언제 유지되고 언제 사라지는지 아는 것이다. 앱 컨테이너는 다시 빌드하고 다시 띄우면 된다. 하지만 DB 데이터는 실수로 지우면 복구하기 어렵다.

이번 실습의 목표는 postgres_data 볼륨, schema.sql 초기화, down -v의 의미를 정확히 구분하는 것이다.

현재 DB 볼륨 구조

현재 Compose 파일은 PostgreSQL 데이터 디렉터리를 named volume에 연결한다.

db:
  volumes:
    - postgres_data:/var/lib/postgresql/data
    - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro

volumes:
  postgres_data:

첫 번째 줄은 DB 데이터 보존용이다.

- postgres_data:/var/lib/postgresql/data

두 번째 줄은 초기화 SQL 주입용이다.

- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro

둘은 역할이 완전히 다르다. postgres_data는 DB가 실제 데이터를 쓰는 곳이고, schema.sql은 데이터 디렉터리가 비어 있을 때 처음 실행되는 초기화 파일이다.

볼륨 목록 확인

Compose를 한 번 실행한 뒤 볼륨을 확인한다.

docker volume ls

프로젝트 이름을 discodeit으로 고정했다면 볼륨 이름은 다음처럼 보일 수 있다.

discodeit_postgres_data
discodeit_app_storage

볼륨 상세 정보는 다음 명령으로 본다.

docker volume inspect discodeit_postgres_data

여기서 실제 마운트 위치를 볼 수 있지만, 보통 직접 수정하지 않는다. Docker가 관리하는 저장소로 생각하면 된다.

schema.sql이 다시 실행되지 않는 이유

PostgreSQL 컨테이너는 처음 시작할 때 데이터 디렉터리가 비어 있으면 초기화 과정을 수행한다. 이때 /docker-entrypoint-initdb.d 아래의 SQL 파일을 실행한다.

하지만 postgres_data 볼륨에 이미 DB가 만들어져 있으면 초기화 단계가 생략된다. 그래서 schema.sql을 수정한 뒤 컨테이너를 재시작해도 변경사항이 자동 반영되지 않는다.

상황별로 선택지가 다르다.

상황처리
처음부터 새 DB로 다시 만들고 싶다docker compose down -v 후 다시 up
기존 데이터를 유지하고 스키마만 바꾸고 싶다직접 SQL 실행 또는 마이그레이션 도구 사용
실수로 볼륨을 지우면 안 된다down -v 금지

개발용 DB를 완전히 초기화하기

학습용 데이터라서 지워도 된다면 다음 순서로 초기화한다.

docker compose down -v
docker compose up -d

첫 번째 명령은 컨테이너, 네트워크, named volume을 함께 삭제한다. 두 번째 명령은 새 볼륨을 만들고 PostgreSQL 초기화를 다시 수행한다.

운영 데이터에는 절대 습관적으로 쓰지 않는다

down -v는 DB 파일을 지운다. 로컬 실습 데이터처럼 잃어도 되는 경우에만 사용한다.

기존 볼륨을 유지하고 SQL 확인하기

DB 컨테이너가 떠 있다면 내부에서 psql을 실행할 수 있다.

docker compose exec db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt"'

테이블 목록이 보이면 DB 접속과 초기 스키마가 정상이다.

특정 테이블의 row 수를 확인하려면 다음처럼 실행한다.

docker compose exec db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select count(*) from users;"'

테이블 이름은 실제 schema.sql에 맞게 바꾼다.

백업 후 초기화하기

초기화가 필요하지만 현재 데이터를 보관하고 싶다면 먼저 덤프를 만든다.

docker compose exec db sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > backup.sql

그다음 개발용 볼륨을 삭제하고 다시 띄운다.

docker compose down -v
docker compose up -d

복원은 새 DB가 떠 있는 상태에서 수행한다.

docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"' < backup.sql

PowerShell에서는 리다이렉션 인코딩이나 경로 문제로 명령이 다르게 동작할 수 있다. 덤프와 복원은 중요한 데이터에 적용하기 전에 작은 테스트 DB로 먼저 확인한다.

DB 포트 노출 판단

DB 컨테이너의 포트 매핑은 선택 사항이다.

db:
  ports:
    - "${POSTGRES_HOST_PORT:-5432}:5432"

이 설정을 유지하면 호스트의 DB 클라이언트에서 접속하기 쉽다. 예를 들어 IntelliJ Database 탭이나 DBeaver에서 localhost:5432로 접근할 수 있다.

반대로 앱 컨테이너만 DB에 접근하면 된다면 이 설정을 제거해도 된다. Compose 내부 네트워크에서는 db:5432로 통신하기 때문이다.

필요권장
로컬 DB 클라이언트로 직접 접속ports 유지
앱 컨테이너만 DB 사용ports 제거 가능
5432 포트 충돌이 자주 발생${POSTGRES_HOST_PORT:-5432}로 외부 포트 조정

체크리스트

  • postgres_data가 DB 데이터 보존용이라는 점을 이해했다.
  • schema.sql은 빈 데이터 디렉터리에서만 자동 실행된다는 점을 이해했다.
  • docker compose downdocker compose down -v의 차이를 설명할 수 있다.
  • DB 초기화 전에 백업이 필요한 상황을 구분할 수 있다.
  • DB 포트 노출이 앱 내부 통신에 필요한 것은 아니라는 점을 확인했다.

이제 마지막 실습에서 전체 실행과 문제 해결 루틴을 정리한다.