도커를 사용하다 보면 컨테이너가 아닌 볼륨에 저장된 데이터를 백업하거나, 테스트를 위해 다른 볼륨으로 복제해야 하는 경우가 자주 발생합니다.
단순히 docker cp 명령어를 생각할 수 있지만, 이 명령어는 컨테이너의 파일 시스템과 호스트 간의 복사만 지원하며 도커가 관리하는 볼륨에 직접 접근하지 못합니다.
이 글에서는 도커 볼륨을 복사하는 올바른 방법을 소개합니다. 단순히 명령어를 나열하는 것이 아니라, '왜' 이 방식을 사용해야 하는지 그 원리에 초점을 맞춥니다. 이 원리를 이해하면 명령어를 외우지 않고도 필요할 때마다 자연스럽게 응용할 수 있습니다.
핵심 원리는 간단합니다.
도커 볼륨을 조작하는 가장 안전하고 '도커스러운' 방법은, 해당 볼륨에 접근할 수 있는 '임시 컨테이너'를 다리(bridge)로 활용하는 것입니다.
1. 기존 볼륨을 새 볼륨으로 복사하기 (Volume-to-Volume)
가장 흔한 시나리오입니다. 운영 중인 db_data 볼륨을 테스트용 db_data_test 볼륨으로 복제하고 싶을 수 있습니다.
🤔 WHY: 왜 임시 컨테이너를 사용할까?
도커 볼륨은 호스트 파일 시스템 어딘가( /var/lib/docker/volumes/... 등)에 저장되지만, 도커 데몬이 이 경로를 관리합니다. 이 경로에 직접 접근해 cp 명령어를 사용하는 것은 권장되지 않으며, 권한 문제나 데이터 일관성 문제를 일으킬 수 있습니다.
대신, 우리는 두 개의 볼륨을 동시에 마운트한 임시 컨테이..너를 실행합니다.
-
컨테이너가
/from경로에 원본 볼륨(source_volume)을 마운트합니다. -
컨테이너가
/to경로에 대상 볼륨(new_volume)을 마운트합니다. -
컨테이너는 실행되자마자
/from의 모든 데이터를/to로 복사하는 간단한 리눅스 명령어(cp또는tar)를 실행합니다. -
명령이 끝나면 컨테이너는 자동으로 파기됩니다(
--rm옵션).
이 컨테이너는 오직 데이터 복사만을 위한 '도구'로 사용됩니다.
🚀 HOW: 명령어 예제
source_data 볼륨의 데이터를 target_data 볼륨으로 복사하는 예제입니다.
- 테스트용 볼륨 생성 (선택 사항)
docker volume create source_data
docker volume create target_data
# (source_data에 데이터가 있다고 가정합니다.)
- 임시 컨테이너를 이용한 복사
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cp -a /from/. /to/"
💡 명령어 해설
-
docker run --rm:--rm플래그는 컨테이너가 작업을 완료하고 종료될 때 즉시 컨테이너를 삭제하라는 의미입니다. 임시 작업에 필수입니다. -
-v source_data:/from:source_data볼륨을 컨테이너 내부의/from디렉터리에 마운트합니다. -
-v target_data:/to:target_data볼륨을 컨테이너 내부의/to디렉터리에 마운트합니다. -
alpine:cp나sh같은 기본 유틸리티를 포함하면서도 용량이 매우 작은alpine리눅스 이미지를 사용합니다. -
sh -c "...": alpine 컨테이너가 실행될 때 내릴 명령어입니다. -
cp -a /from/. /to/:-
-a(archive): 이 플래그가 핵심입니다. 단순 복사(cp -r)가 아니라 소유권, 권한, 타임스탬프 등 모든 속성을 보존하며 복사합니다. 데이터베이스 파일 등 민감한 데이터를 다룰 때 매우 중요합니다. -
/from/.:/from디렉터리가 아닌,/from내부의 모든 콘텐츠 (숨겨진 파일 포함)를 의미합니다.
-
2. 볼륨 데이터를 호스트 파일 시스템으로 복사하기 (백업)
볼륨의 데이터를 내 로컬 머신이나 서버의 특정 디렉터리에 .tar 파일 등으로 백업하고 싶을 때 사용합니다.
🤔 WHY: 어떻게 작동하는가?
원리는 1번과 동일합니다. 다만, 대상이 '도커 볼륨'이 아니라 '호스트 디렉터리'로 바뀌었을 뿐입니다.
도커는 호스트의 특정 디렉터리를 컨테이너에 마운트하는 바인드 마운트(Bind Mount) 기능을 지원합니다.
-
컨테이너가
/data경로에 원본 볼륨(source_volume)을 마운트합니다. -
컨테이너가
/backup경로에 호스트의 특정 디렉터리($(pwd)/backup)를 마운트합니다. -
컨테이너는
/data의 내용을/backup디렉터리로 복사(또는 압축)합니다. -
이 작업은 컨테이너 안에서 일어났지만,
/backup은 실제 호스트 디렉터리와 연결되어 있으므로 결과물은 호스트에 남게 됩니다.
🚀 HOW: 명령어 예제
source_data 볼륨의 데이터를 현재 위치($(pwd))의 backup 디렉터리로 복사합니다.
# 호스트에 백업받을 디렉터리 생성
mkdir -p $(pwd)/backup
docker run --rm \
-v source_data:/data:ro \
-v $(pwd)/backup:/backup \
alpine \
cp -a /data/. /backup/
💡 명령어 해설
-
-v source_data:/data:ro::ro(Read-Only) 플래그를 추가했습니다. 백업은 데이터를 읽기만 하면 되므로, 실수로 원본 볼륨을 수정하는 것을 방지하기 위해 읽기 전용으로 마운트하는 것이 좋습니다. -
-v $(pwd)/backup:/backup:source_data(볼륨 이름)와 달리,/로 시작하거나$(pwd)(현재 경로)를 포함한 절대/상대 경로는 호스트의 디렉터리를 의미합니다.
3. 핵심 복사 팁 (Tips)
팁 1: tar를 사용한 효율적인 복사 (압축 백업)
cp 명령어 대신 tar를 사용하면 여러 이점이 있습니다. 특히 데이터를 아카이브 파일(.tar.gz)로 한 번에 묶어 백업할 때 유용합니다.
Volume-to-Volume (tar 사용)
cp보다 빠를 수 있으며, 특히 파일이 많을 때 효율적입니다.
docker run --rm \
-v source_data:/from \
-v target_data:/to \
alpine \
sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
-
cd /from && tar -cf - .:/from으로 이동해, 현재 디렉터리(.)의 내용을tar로 묶어(c) 파일(f)이 아닌 표준 출력(-)으로 보냅니다. -
| (cd /to && tar -xf -): 파이프(|)로 표준 출력을 받아,/to디렉터리에서tar압축을 풉니다(x).
Volume-to-Host (압축 백업)
source_data 볼륨의 내용을 backup.tar.gz 파일로 압축하여 호스트에 저장합니다.
docker run --rm \
-v source_data:/data:ro \
-v $(pwd):/backup \
alpine \
tar -czf /backup/backup.tar.gz -C /data .
-
tar -czf /backup/backup.tar.gz ...:c(생성),z(gzip 압축),f(파일로)/backup/backup.tar.gz파일을 만듭니다. -
-C /data .: 이 부분이 중요합니다. /data 디렉터리로 먼저 이동(Change directory) 한 뒤, 그 안의 모든 것(.
)을 압축합니다. 이렇게 하면 tar 파일 내부에 불필요한 /data 경로가 포함되지 않습니다.
팁 2: 호스트 파일을 볼륨으로 복원하기
백업의 반대, 즉 복원도 동일한 원리를 사용합니다. cp의 방향만 바꾸면 됩니다.
# $(pwd)/backup 디렉터리의 데이터를 new_data 볼륨으로 복원
docker run --rm \
-v new_data:/data \
-v $(pwd)/backup:/backup:ro \
alpine \
cp -a /backup/. /data/
요약
도커 볼륨을 다루는 핵심은 "컨테이너를 도구로 사용한다" 는 사고방식입니다. 호스트에서 직접 볼륨 파일을 건드리는 대신, 필요한 볼륨과 디렉터리를 장착한 임시 컨테이너를 실행하여 그 안에서 안전하게 cp나 tar 같은 표준 리눅스 명령을 실행하는 것.
이 원리만 기억하면 어떤 상황에서든 볼륨 데이터를 자유롭게 복사하고, 백업하고, 복원할 수 있을 것입니다.
댓글이 없습니다.