About

Postgres 볼륨 경로가 3년 틀렸는데 멀쩡했던 이유 — VOLUME 선언이 몰래 붙인 이름 없는 볼륨

데이터는 경로가 아니라 볼륨 이름을 따라간다. down 을 쓰는 사람만 DB 를 잃는다

docker-compose 의 Postgres 볼륨이 db:/data/db 로 잡혀 있었다. MongoDB 경로다. 3년 전 처음 세팅할 때 내가 넣은 실수였다. 그런데 나는 그동안 DB 가 날아간 적이 한 번도 없었고, 동료는 「컨테이너를 다시 띄울 때마다 DB 가 사라진다」 고 했다.

결론부터. 경로가 틀려도 Postgres 는 잘 돈다. 이미지가 VOLUME 으로 선언한 경로에 Docker 가 이름 없는 볼륨을 붙여 주기 때문이다. 그 볼륨은 down 하는 순간 버려진다. 지금 쓰는 compose 파일의 DB 볼륨 줄을 한 번 확인해 볼 만하다.

무엇이 붙어 있었나

db:
  image: postgres:16
  volumes: ["db:/data/db"]   # Postgres 는 여기를 안 쓴다

공식 postgres 16 이미지의 Dockerfile 에는 이 두 줄이 있다.

ENV PGDATA /var/lib/postgresql/data
VOLUME /var/lib/postgresql/data

VOLUME 은 「이 경로는 컨테이너 밖에 둔다」 는 선언이다. compose 가 그 경로에 아무것도 안 붙이면 Docker 가 이름 없는(anonymous) 볼륨을 하나 만들어 붙인다. 실제 모습은 이랬다.

Before - db:/data/db container /data/db /var/lib/postgresql/data PGDATA · Postgres writes here named volume "db" — empty for 3 years anonymous volume a3f9c1… real data · made by VOLUME in the image down → up : a new empty one is made After - db:/var/lib/postgresql/data /var/lib/postgresql/data PGDATA named volume "db" — survives down

이름 있는 볼륨 db 는 아무도 안 쓰는 /data/db 에 붙어 3년 동안 비어 있었다. 진짜 데이터는 해시 이름이 붙은 이름 없는 볼륨에 있었다.

왜 나만 멀쩡했나 — 습관이 갈랐다

명령 고치기 전 (이름 없는 볼륨) 고친 뒤 (이름 있는 볼륨)
stop · start · restart 남음 남음
up -d 로 컨테이너 재생성 남음 남음
down → up 빈 DB 남음
rm 뒤 up, up -V 빈 DB 남음
down -v, volume prune 빈 DB 빈 DB

up 으로 컨테이너를 새로 만들 때 compose 는 이전 컨테이너의 이름 없는 볼륨을 넘겨받는다. 공식 문서의 -V, --renew-anon-volumes 설명이 「이전 컨테이너에서 데이터를 가져오는 대신 이름 없는 볼륨을 다시 만든다」 이니, 기본은 넘겨받기다. 나는 up 과 stop 만 썼고 동료는 down 으로 정리하는 습관이 있었다. 버그는 하나인데 증상은 사람마다 달랐다.

처음에 헷갈렸던 것

「경로가 같으면 데이터도 남아야 하지 않나」 라고 생각했다. 아니었다. 컨테이너를 새로 만들면 파일 시스템도 이미지에서 새로 펼쳐진다. 데이터가 남는 건 그 경로에 같은 이름의 볼륨이 다시 붙을 때뿐이다. 데이터는 경로가 아니라 볼륨 이름을 따라간다.

/var/lib/postgresql/data 는 Mac 의 경로도 아니다. 컨테이너 안 경로이고, 실제 파일은 Docker Desktop VM 안 /var/lib/docker/volumes/<프로젝트명>_db/_data 에 있다. Homebrew 로 깐 Postgres 와도 섞이지 않는다.

내 Mac 에는 어디에도 안 붙은 볼륨(docker volume ls -qf dangling=true)이 32개 있었다. 몇 개가 지난 down 때 버려진 DB 인지는 아직 세어 보지 않았다.

다른 DB 의 줄을 복사해 오면 똑같이 터진다

공식 이미지의 VOLUME 은 제각각이다 (각 Dockerfile · Docker Hub 설명, 2026-10-19 확인).

이미지 VOLUME
postgres 17 이하 /var/lib/postgresql/data
postgres 18 이상 /var/lib/postgresql (PGDATA 는 /var/lib/postgresql/18/docker)
mysql /var/lib/mysql
mongo /data/db, /data/configdb
redis /data

다른 프로젝트 compose 에서 볼륨 줄만 가져오면 이번 같은 일이 난다. Postgres 18 로 올릴 때도 같은 자리를 다시 본다. Docker Hub 설명은 18 부터 마운트를 /var/lib/postgresql 로 하라고 적고 있다. 17 시절의 :/var/lib/postgresql/data 줄을 그대로 두면 PGDATA 가 그 밖에 놓인다.

확인하는 법

docker image inspect postgres:16 --format '{{json .Config.Volumes}}'
docker inspect $(docker compose ps -q db) --format '{{json .Mounts}}'

두 번째 결과에서 PGDATA 경로에 붙은 볼륨의 Name 이 64자 해시라면 이 함정이다.

볼륨 세 가지, 언제 무엇을

종류 이럴 때
이름 있는 볼륨 (db:/var/lib/postgresql/data) 로컬 개발 DB 의 기본. down 해도 남는다
bind mount (./tmp/pg:/var/lib/postgresql/data) 데이터를 폴더째 보거나 들고 다니고 싶을 때
이름 없는 볼륨 버려도 되는 캐시. DB 에는 쓰지 않는다

로컬 개발 환경이 사람마다 다르게 깨진다면, 대개 이런 숨은 기본값 하나가 원인이다. 같이 들여다볼 사람이 필요하면 https://www.negabaro.com/contact 로 연락 주면 된다.

동작 흐름

1

이미지 Dockerfile 의 VOLUME 이 PGDATA 경로를 「밖에 둘 곳」 으로 선언

2

compose 가 그 경로에 아무것도 안 붙이면 Docker 가 이름 없는 볼륨을 붙인다

3

up 으로 재생성하면 이전 이름 없는 볼륨을 넘겨받아 데이터가 남는다

4

down → up 이면 새 이름 없는 볼륨이 붙어 빈 DB 가 된다

← Portless란? localhost 포트 번호를 myapp.localhost 이름으로 바꾸는 원리 로컬 개발 화면을 Mac 앱으로 — Electron 말고 manifest 한 장과 launchd →