• 도커로 로컬 DB 테스트 환경 구축 문의드립니다

    요즘 프로젝트 하면서 도커 컨테이너에 PostgreSQL 같은 DB 띄워서 테스트하는 게 기본 루틴이 됐어요.
    근데 매번 컨테이너 띄울 때마다 데이터 영속성 관리나 볼륨 마운트 설정 부분이 좀 헷갈리네요.

    특히 로컬에서 개발할 때마다 DB 데이터를 초기화하거나, 혹은 특정 시점의 데이터를 유지하면서 테스트하고 싶은데, 어떤 방식으로 볼륨을 마운트 하는 게 가장 효율적인지 궁금합니다.

    혹시 컨테이너 환경에서 개발용 DB를 띄울 때, 데이터 관리가 가장 깔끔하고 나중에 다시 찾아보기 쉬운 방법 같은 게 있을까요?
    복잡하게 설정하는 것보다, 그냥 '이건 이렇게 하면 무조건 편하다' 하는 정석적인 방법이 알고 싶습니다.

  • 와, 이 주제는 정말 모든 개발자가 한 번쯤 겪고, 또 가장 헷갈리는 부분이기도 합니다.
    저도 처음에 도커 DB를 붙이면서 볼륨 설정할 때마다 "이거 영구 저장되는 건가요?", "껐다 켜면 데이터 사라지나요?" 이 질문만 백 번은 한 것 같습니다.
    결론부터 말씀드리자면, 질문자님이 원하시는 "가장 깔끔하고 정석적인 방법"은 Docker Compose를 사용하고, Named Volume을 활용하며, 초기화 스크립트(Initialization Scripts)를 활용하는 조합입니다.
    이게 왜 정석인지, 그리고 상황별로 어떻게 접근해야 하는지 조금 더 자세하게 풀어서 설명드릴게요.
    --- ### 📌 1.
    도커 볼륨의 종류 이해하기 (가장 중요!) 먼저, 데이터 영속성 관점에서 볼륨의 세 가지 종류를 구분하는 게 핵심입니다.
    1.
    Bind Mount (바인드 마운트):
    호스트 PC의 특정 폴더 경로를 컨테이너 내부 폴더에 직접 연결하는 방식입니다.
    ./data:/var/lib/postgresql/data 이런 식으로 설정하는 거죠.
    장점은 호스트 PC에서 파일을 직접 열어보거나 수정할 수 있어서 디버깅이 편하다는 점입니다.
    단점은, 호스트 PC의 구조에 종속적이고, 여러 개발자 간의 환경 일관성이 깨지기 쉽다는 점입니다.
    (A 개발자는 C 드라이브에, B 개발자는 D 드라이브에 같은 경로로 설정할 수 없죠.) 2.
    Anonymous/Ephemeral Volume (임시 볼륨):
    볼륨을 지정해주지 않고 단순히 컨테이너가 사용할 공간을 주는 겁니다.
    가장 가볍지만, 컨테이너가 중지되거나 삭제되면 데이터가 100% 사라집니다. 테스트용으로 "딱 이것만 돌려보고 휘발시켜도 되는" 임시 테스트에만 적합합니다.
    3.
    Named Volume (이름 지정 볼륨):
    Docker가 내부적으로 관리하는 이름의 볼륨입니다.
    db_data:/var/lib/postgresql/data 이런 식으로 사용합니다.
    실무에서 DB 데이터를 다룰 때 가장 많이 쓰이고, 가장 추천하는 방식입니다. 장점은 Docker가 알아서 호스트 PC의 어느 곳에, 어떻게 안전하게 저장할지 관리해 주기 때문에, 개발자 간의 환경 의존성이 사라지고 "데이터는 Docker가 알아서 잘 보관해 줄 거야"라는 안정감을 줍니다.
    --- ### 📌 2.
    상황별 최적의 데이터 관리 전략 (시나리오 분리) 질문자님이 원하는 두 가지 시나리오(초기화 vs.
    유지)에 맞춰 볼륨 사용법을 분리해서 설명드릴게요.

    🧪 시나리오 A: 매번 깨끗한 상태에서 테스트하고 싶을 때 (Clean Slate Test) 이건 주로 단위 테스트(Unit Test)나, 특정 기능을 처음부터 다시 테스트할 때 유용합니다.

    어제 돌렸던 데이터가 오늘 테스트에 영향을 주는 걸 원치 않을 때 쓰는 방법이죠.
    ✅ 추천 방법: Named Volume 사용 + 데이터 초기화 스크립트 활용 1.
    볼륨 설정: docker-compose.yml에서 db_volume 같은 이름의 Named Volume을 정의합니다.
    2.
    데이터 초기화: PostgreSQL 컨테이너가 처음 시작될 때, 컨테이너 내부의 특정 디렉토리(pgdata/init)에 SQL 파일들을 넣어주면, 컨테이너가 부팅되면서 해당 SQL 파일들을 순서대로 실행해 줍니다.
    3.
    데이터 삭제: 만약 데이터를 완전히 초기화하고 싶다면, 가장 간단한 방법은 해당 Named Volume을 직접 삭제하는 겁니다.
    docker volume rm [your_volume_name] 명령어를 실행하면, 그 볼륨에 있던 모든 데이터가 깨끗하게 사라집니다.
    💡 실무 팁: 매번 삭제하고 다시 띄우는 게 번거롭다면, 테스트 전에 docker-compose down -v를 한 번 돌려주는 습관을 들이는 게 가장 빠릅니다.
    (-v 옵션이 볼륨까지 같이 삭제해 줍니다.) #### 💾 시나리오 B: 특정 시점의 데이터를 유지하며 테스트하고 싶을 때 (State Retention Test) 예를 들어, '회원 가입' 기능 테스트를 할 때, 이미 가입된 사용자 데이터가 사라지면 안 되고, 그 상태에서 '비밀번호 찾기' 기능을 테스트하고 싶을 때가 있죠.
    ✅ 추천 방법: Named Volume 사용 + 데이터 백업/복원 (Dump/Restore) 이 경우에는 볼륨 자체를 건드리는 것보다, 데이터베이스 자체의 기능을 쓰는 게 훨씬 안전하고 깔끔합니다.
    1.
    데이터 덤프 (Export): 테스트를 시작하기 전에, 현재 DB의 데이터를 pg_dump 같은 툴로 SQL 파일 형태로 백업합니다.
    pg_dump -U user -h localhost -p 5432 dbname > backup_pre_test.sql 2.
    데이터 로드 (Import): 테스트가 끝나고, 다음 테스트 세션을 시작할 때 이 backup_pre_test.sql 파일을 이용해 DB를 덮어씌우거나(Overwrite), 아니면 필요한 부분만 복원(Restore)합니다.
    📌 주의점: 만약 컨테이너가 너무 커서 덤프/복원이 부담스럽다면, Named Volume을 사용하되, 테스트 직전에 컨테이너를 멈추고, 볼륨을 잠깐 다른 곳에 백업본으로 복사해두는 수동적인 방법도 있습니다.
    --- ### 🛠️ 3.
    가장 깔끔한 '표준 템플릿' 구성 (Docker Compose 예시) 실제로 제가 가장 많이 쓰고, 가장 안정적이라고 느끼는 구조는 아래와 같은 docker-compose.yml 기반의 설정입니다.

    volumes: # 1.
    데이터를 영구 보존할 Named Volume 사용 - db_data:/var/lib/postgresql/data # 2.
    초기화 스크립트가 들어갈 위치 (컨테이너 시작 시 자동 실행됨) - ./scripts/init:/docker-entrypoint-initdb.d ports: - "5432:5432" restart: always volumes: # 여기에 이름을 지정하여 Docker가 관리하게 합니다.
    db_data: ``` **이 설정의 장점을 다시 정리하자면:** 1.
    **`db_data:` (Named Volume):** 데이터는 Docker 엔진이 관리하는 영역에 안전하게 저장됩니다.
    2.
    **`./scripts/init:` (Init Scripts):** 이 폴더에 `01_create_user.sql`, `02_create_table.sql` 같은 SQL 파일을 넣어두면, `docker-compose up`을 할 때 **컨테이너가 처음 실행되는 시점에 이 파일들이 순서대로 실행**되면서 DB 구조가 세팅됩니다.
    3.
    **환경 변수 사용:** 비밀번호나 DB 이름 같은 민감한 정보는 YAML 파일에 직접 적지 말고, `.env` 파일을 만들어서 `environment:` 섹션에서 참조하는 것이 보안상 가장 좋습니다.
    --- ### ⚠️ 개발자가 자주 하는 실수 3가지와 해결책 1.
    **실수 1: `docker-compose up`만 돌리고, `docker-compose down`을 안 하는 경우** * **문제:** 컨테이너만 멈추고 볼륨 데이터는 남아있기 때문에, 다음 테스트 시점의 데이터가 꼬여서 원인을 알 수 없는 버그가 발생합니다.
    * **해결:** 테스트 세션이 끝날 때는 무조건 `docker-compose down -v`를 사용하세요.
    (`-v`가 볼륨까지 깔끔하게 삭제해 줍니다.) 2.
    **실수 2: 환경 변수를 코드에 하드코딩하는 경우** * **문제:** 로컬 개발용으로 하드코딩하면, 다른 팀원이 이 코드를 받거나 다른 환경에 적용할 때마다 DB 접속 정보가 꼬이게 됩니다.
    * **해결:** 반드시 `.env` 파일을 도입하고, 코드 레벨에서도 환경 변수(`process.env.DB_PASSWORD` 등)를 읽어오도록 수정해야 합니다.
    3.
    **실수 3: Bind Mount를 DB 데이터 디렉토리에 사용하는 경우** * **문제:** 호스트 PC의 파일 시스템 권한 문제나, OS가 가진 파일 시스템의 특성 때문에 데이터 쓰기/읽기 권한 문제가 터질 확률이 높습니다.
    * **해결:** DB의 데이터 디렉토리(`data/` 폴더)는 **항상 Named Volume**을 사용하세요.
    이 정도면 충분히 복잡한 내용을 커버했을 거라고 생각합니다.
    결국 핵심은 **"데이터는 Docker가 관리하게 (Named Volume)"** 하고, **"초기 세팅은 스크립트가 맡고 (Init Scripts)"**, **"테스트 종료 시에는 깨끗하게 정리한다 (down -v)"** 이 루틴을 몸에 익히는 겁니다.
    이거 한 번만 제대로 세팅해 놓으면, 이후 프로젝트에서는 DB 환경 구축 시간이 10분도 안 걸릴 겁니다.
    화이팅하시고요!