Docker 재시작 후 PostgreSQL 데이터가 사라지는 이유와 영구 저장 방법

 Docker로 PostgreSQL을 운영하다가 한 번쯤은 이런 상황을 겪게 된다.

컨테이너를 재생성했더니 데이터베이스가 텅 비어 있었다. 처음에는 PostgreSQL 자체 문제인 줄 알았다. 로그를 확인하고 설정을 점검했지만 이상이 없었다. 원인은 Docker 볼륨 설정이었다.

UGREEN DXP4800PLUS NAS에서 쇼츠 자동화 시스템과 트레이딩 봇을 운영하면서 이 문제를 직접 겪었다. 이 글에서는 PostgreSQL 데이터가 삭제되는 원인과 NAS 환경에서 데이터를 영구적으로 보존하는 방법을 정리한다.


왜 데이터가 사라지는가

Docker 컨테이너는 애플리케이션 실행 환경만 보관한다. 

데이터를 별도 저장소에 보관하지 않으면 컨테이너 삭제 시 함께 사라진다.

가장 흔한 실수는 볼륨 설정 없이 PostgreSQL을 실행하는 것이다.

yaml
# 잘못된 구성 - 데이터가 사라짐
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword

이 상태에서 docker compose downdocker compose up을 다시 실행하면 데이터가 사라진다. docker compose down은 컨테이너를 삭제하기 때문이다.

bash
# 이 명령어가 데이터를 삭제한다
docker compose down

# 이건 괜찮음 (컨테이너 중지만, 삭제 안 함)
docker compose stop

Docker Volume 개념

데이터를 영구 보존하려면 볼륨(Volume)을 사용해야 한다.

Docker Volume 방식은 두 가지다.

Named Volume (도커 관리 볼륨)

yaml

services:
  postgres:
    image: postgres:15-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Docker가 볼륨을 관리한다. 경로는 /var/lib/docker/volumes/ 아래에 저장된다.

Bind Mount (직접 경로 지정)

yaml

services:
  postgres:
    image: postgres:15-alpine
    volumes:
      - /volume2/docker/postgres/data:/var/lib/postgresql/data

호스트의 특정 경로에 직접 저장한다. NAS 환경에서는 이 방식이 더 유리하다.


NAS 환경에서 올바른 구성

UGREEN DXP4800PLUS NAS에서는 Bind Mount 방식을 권장한다.

이유:

  • NAS 파일 관리자에서 직접 데이터 확인 가능
  • 백업이 쉬움
  • 데이터 위치가 명확함
yaml
services:
  postgres:
    image: postgres:15-alpine
    container_name: shorts-postgres
    environment:
      POSTGRES_DB: shorts
      POSTGRES_USER: shorts
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      TZ: Asia/Seoul
    volumes:
      - /volume2/docker/shorts-trend/postgres/data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U shorts"]
      interval: 5s
      timeout: 5s
      retries: 5

/volume2/docker/shorts-trend/postgres/data 경로에 PostgreSQL 데이터가 저장된다. 컨테이너를 삭제해도 이 폴더는 남아있다.


볼륨 확인 방법

bash
# 현재 Docker 볼륨 목록
docker volume ls

# 특정 볼륨 상세 정보
docker volume inspect postgres_data

# Bind Mount 확인 (실제 경로에 파일 있는지)
ls /volume2/docker/shorts-trend/postgres/data

정상적으로 설정됐다면 ls 결과에 PG_VERSION, base, global 등의 파일과 폴더가 보인다.

[ls /volume2/docker/ 결과]

UGREEN DXP4800PLUS NAS /volume2/docker 폴더 구조 서비스별로 분리된 데이터 저장 경로


실제로 겪은 사례

트레이딩 봇 시스템을 개발하면서 이 문제를 겪었다. 

포지션 데이터, 주문 내역, 체결 데이터를 PostgreSQL에 저장하고 있었는데 컨테이너를 재생성할 때마다 데이터가 초기화됐다.

쇼츠 자동화 시스템에서도 같은 실수를 했다. 

수집한 영상 데이터 수백 개가 사라진 후에야 볼륨 설정을 제대로 잡았다. 다행히 테스트 환경이었지만 실서비스였다면 다시 수집하는 데 수 시간 이상이 걸릴 상황이었다.

현재는 /volume2/docker 하위에 서비스별로 폴더를 분리해서 데이터를 영구 보존하고 있다.


주의사항

docker compose down vs stop

bash
# 컨테이너 삭제 (볼륨 없으면 데이터 삭제)
docker compose down

# 컨테이너 중지만 (데이터 유지)
docker compose stop

# 볼륨까지 삭제 (절대 주의)
docker compose down -v

docker compose down -v 는 Named Volume까지 삭제한다. 절대 운영 환경에서 실수로 실행하지 않도록 주의해야 한다.

폴더 권한 문제

NAS에서 Bind Mount 사용 시 폴더 권한 오류가 발생할 수 있다.

bash
# PostgreSQL 컨테이너는 999:999 권한 필요
chown -R 999:999 /volume2/docker/postgres/data

컨테이너 시작 시 Permission denied 오류가 나면 이 명령어로 해결된다.


마무리

Docker PostgreSQL 데이터 손실은 볼륨 설정 하나로 해결된다. 핵심은 두 가지다.

첫째, docker compose down은 컨테이너를 삭제한다. 볼륨 없이 사용하면 데이터도 함께 사라진다.

둘째, NAS 환경에서는 Bind Mount 방식으로 /volume2/docker/ 하위에 직접 경로를 지정하는 것이 관리하기 편하다.

실서비스 전에 반드시 docker compose down && docker compose up으로 데이터 유지 여부를 테스트해보는 것을 권장한다.


관련 글

댓글

이 블로그의 인기 게시물

UGREEN DXP4800PLUS NAS로 유튜브 쇼츠 자동화 시스템 구축기 (Docker · FastAPI · PostgreSQL · Edge-TTS)

YouTube Data API 쿼터 초과를 피하는 방법 (700개 쇼츠 수집 사례)

FastAPI app.mount 사용 후 API가 404가 되는 이유와 해결 방법