이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Docker volume은 container 교체와 데이터 보존을 어떻게 분리하는가?
  • named volume, bind mount, container writable layer는 운영에서 어떻게 다르게 다뤄야 하는가?
  • volume 삭제, mount 경로 오류, 백업 누락은 어떤 장애를 만드는가?

개요

Container는 교체 가능한 실행 단위다.

따라서 보존해야 하는 데이터는 container 내부 writable layer에만 두면 안 된다.

Docker volume은 container를 삭제하거나 image를 교체해도 유지해야 하는 파일을 분리하는 장치다.

Spring 백엔드에서는 업로드 파일, 임시 export, local 개발용 DB 데이터, 로그, cache 파일의 보존 기준을 명확히 해야 한다.

세 가지 저장 위치

Docker에서 파일은 크게 세 위치에 있을 수 있다.

Container writable layer:

  • container와 함께 사라질 수 있다.
  • 임시 파일에는 적합하지만 영속 데이터에는 위험하다.

Named volume:

  • Docker가 관리하는 volume이다.
  • container를 재생성해도 남을 수 있다.

Bind mount:

  • host 경로를 container에 연결한다.
  • host 권한, 백업, 경로 관리가 중요하다.
docker volume ls
docker inspect order-api --format '{{json .Mounts}}'

Compose 예시

local 개발이나 소규모 운영에서는 Compose에서 volume을 명시한다.

services:
  app:
    image: order-api:3f21a9c
    volumes:
      - ./logs:/var/log/order-api
  db:
    image: postgres:16
    volumes:
      - order-db-data:/var/lib/postgresql/data
 
volumes:
  order-db-data:

여기서 order-db-data는 named volume이다.

반면 ./logs는 host 현재 경로에 의존하는 bind mount다.

운영에서는 상대 경로 bind mount보다 절대 경로와 owner를 명확히 하는 편이 안전하다.

Spring 애플리케이션과 Volume

Spring 애플리케이션에서 파일을 쓰는 위치는 설정으로 고정한다.

app.upload-dir=/data/uploads
logging.file.path=/var/log/order-api

그리고 container 실행 시 해당 경로를 mount한다.

docker run -d \
  --name order-api \
  -v order-api-uploads:/data/uploads \
  -v /var/log/order-api:/var/log/order-api \
  registry.example.com/order-api:3f21a9c

application 설정과 mount 경로가 어긋나면 container 내부에 파일이 쌓이고, 재생성 때 사라질 수 있다.

DB 데이터를 Docker에 둘 때

운영 DB를 단일 Docker volume에 두는 것은 신중해야 한다.

개인 프로젝트나 개발 환경에서는 유용하지만, 기업 운영에서는 managed DB, backup, PITR, monitoring을 우선 검토한다.

Docker volume에 DB 데이터를 둔다면 최소한 다음을 정해야 한다.

  • volume 이름
  • 백업 명령
  • restore 절차
  • host disk 위치
  • 권한과 owner
  • disk usage alert

volume이 있다는 말은 백업이 있다는 뜻이 아니다.

운영 체크리스트

  • 보존해야 할 파일과 버려도 되는 파일을 구분했는가?
  • upload, log, DB data, cache 경로가 문서화되어 있는가?
  • container 내부 경로와 mount 경로가 일치하는가?
  • named volume과 bind mount를 구분하는가?
  • volume backup과 restore를 실제로 시험했는가?
  • mount 경로 owner가 container 실행 사용자와 맞는가?
  • docker compose down -v 사용 위험을 알고 있는가?

장애 신호

  • container 재생성 후 업로드 파일이 사라졌다.
  • DB container 재시작 후 데이터가 초기화됐다.
  • Permission denied로 mounted directory에 파일을 쓰지 못한다.
  • host disk가 full인데 container 안에서는 원인을 찾지 못한다.
  • 로그가 container 내부에만 쌓여 docker rm 후 사라졌다.
  • bind mount 상대 경로가 실행 위치에 따라 달라졌다.
  • 익명 volume이 늘어나 어떤 volume이 실제 데이터인지 모른다.

안전한 완화 조치

데이터 유실이 의심되면 먼저 container 삭제를 멈춘다.

docker volume rm, docker compose down -v, docker system prune --volumes는 특히 조심한다.

현재 mount 정보를 보존한다.

docker inspect order-api --format '{{json .Mounts}}'
docker volume inspect order-db-data

백업 없이 volume을 조작하지 않는다.

파일 권한 문제라면 host 경로 owner와 container user를 함께 확인한다.

인프라 담당자와 공유할 자료

서비스: order-api
증상: 배포 후 업로드 파일 일부 누락
설정: app.upload-dir=/data/uploads
container mount: 없음
이전 실행: bind mount /srv/order/uploads:/data/uploads 사용
요청: 이전 container inspect와 host 경로 파일 존재 여부 확인

volume 문제는 container 설정, Spring 설정, host 경로를 함께 비교해야 한다.

실전 팁

  • container 내부에 남아도 되는 파일과 안 되는 파일을 문서화한다.
  • upload 경로는 Spring 설정과 Docker mount를 함께 리뷰한다.
  • DB data volume은 backup/restore 없이는 운영 데이터로 보지 않는다.
  • volume 삭제 명령은 사고 명령으로 분류한다.
  • bind mount는 host 권한과 경로 이동에 취약하다는 점을 기억한다.

위험 신호!

  • docker compose down -v를 습관적으로 실행한다.
  • 익명 volume에 DB 데이터를 둔다.
  • upload 파일이 container 내부 /tmp/app에 저장된다.
  • volume backup을 해본 적이 없다.
  • mount 경로 owner가 root라 애플리케이션이 쓰지 못한다.

확인 질문

확인 질문

  • container writable layer에 데이터를 저장하면 위험한 이유는 무엇인가?
    • container 삭제나 재생성 시 함께 사라질 수 있어 업로드 파일, DB 데이터, 로그 같은 보존 데이터가 유실될 수 있기 때문이다.
  • named volume과 bind mount의 차이는 무엇인가?
    • named volume은 Docker가 관리하는 저장소이고 bind mount는 host 특정 경로를 container에 연결하는 방식이다.
  • volume 작업 전 반드시 확인해야 할 것은 무엇인가?
    • mount 정보, volume 이름, host 경로, 백업 여부, restore 절차, container 실행 사용자 권한이다.

참고 문서