0. 들어가며: 컨테이너의 휘발성
[BASIC #3]에서 이미지와 컨테이너에 대해 배울 때, 중요한 특징 하나를 언급했었다.
컨테이너는 삭제되면 내부 데이터도 함께 사라진다.
이것이 바로 컨테이너의 휘발성(Volatility) 이다. 컨테이너는 기본적으로 일회용(ephemeral)으로 설계되었다. 언제든지 삭제하고 다시 생성할 수 있는 것이 컨테이너의 장점이지만, 동시에 데이터를 영구적으로 보관해야 하는 상황에서는 큰 문제가 된다. 예를 들어보자.
# MySQL 컨테이너 실행
docker run --name mysql-test -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0
# 컨테이너에 접속해서 데이터베이스 생성
docker exec -it mysql-test mysql -p
# (비밀번호 입력 후) CREATE DATABASE myapp;
# 컨테이너 삭제
docker rm -f mysql-test
# 새 MySQL 컨테이너 실행
docker run --name mysql-test-new -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0
이전 컨테이너에서 생성했던 myapp 데이터베이스는 새 컨테이너에 존재하지 않는다. 데이터가 완전히 사라져버렸다.
이러한 문제를 해결하기 위해 도커는 볼륨(Volume) 기능을 제공한다. 이번 포스팅에서는 컨테이너의 데이터를 영구적으로 저장하는 방법을 알아보겠다.
1. 도커 볼륨의 개념
1.1. 볼륨이 필요한 이유
볼륨은 컨테이너의 데이터를 호스트 머신에 영구적으로 저장하기 위한 메커니즘이다.
[컨테이너] ---(마운트)---> [호스트 파일 시스템]
(읽기/쓰기) (데이터 영구 보관)
- 컨테이너가 삭제되어도 볼륨에 저장된 데이터는 호스트에 그대로 남아 있다.
- 새 컨테이너를 실행할 때 이전에 사용했던 볼륨을 다시 연결하면 데이터를 그대로 사용할 수 있다.
- 여러 컨테이너가 볼륨을 공유할 수도 있다.
1.2. 실생활 비유: 외장 하드디스크
컨테이너를 노트북에 비유해보자.
- 노트북(컨테이너) 자체의 저장공간은 노트북을 초기화하면 모두 사라진다.
- 하지만 외장 하드디스크(볼륨)에 데이터를 저장하면, 노트북을 바꿔도 외장 하드만 연결하면 데이터를 그대로 사용할 수 있다.
- 여러 노트북과 외장 하드를 돌아가며 사용할 수도 있다.
2. 볼륨의 종류
도커는 크게 세 가지 방식으로 데이터를 컨테이너에 연결(마운트)할 수 있다.
2.1. 볼륨 마운트 (Volume Mount)
도커 엔진이 관리하는 전용 저장소 영역을 사용한다.
- 위치: /var/lib/docker/volumes/ (Linux 기준)
- 도커 명령어로 생성/삭제/관리 가능
- 가장 안전하고 권장되는 방식
2.2. 바인드 마운트 (Bind Mount)
호스트 파일 시스템의 특정 경로를 직접 컨테이너에 연결한다.
- 위치: 사용자가 지정한 호스트의 아무 경로나 가능 (예: /home/user/data)
- 호스트와 컨테이너가 파일을 실시간으로 공유
- 주로 개발 환경에서 코드 변경 사항을 즉시 반영할 때 사용
2.3. tmpfs 마운트 (Linux 전용)
메모리에 임시로 저장하는 방식이다.
- 위치: 호스트 메모리 (디스크에 저장되지 않음)
- 컨테이너 종료 시 데이터 자동 삭제
- 임시 파일, 민감한 정보 등에 사용
3. 볼륨 마운트 (Volume Mount)
3.1. 볼륨 생성 및 관리
# 볼륨 생성
docker volume create my-data
# 볼륨 목록 확인
docker volume ls
# 볼륨 상세 정보 확인
docker volume inspect my-data
# 볼륨 삭제
docker volume rm my-data
# 사용하지 않는 볼륨 모두 삭제
docker volume prune
3.2. 볼륨을 사용하는 컨테이너 실행
# 볼륨을 생성하고 컨테이너에 마운트
docker volume create mysql-data
docker run -d \\
--name mysql-db \\
-v mysql-data:/var/lib/mysql \\
-e MYSQL_ROOT_PASSWORD=root \\
mysql:8.0
- v mysql-data:/var/lib/mysql: mysql-data 볼륨을 컨테이너의 /var/lib/mysql 디렉토리에 마운트
- MySQL은 /var/lib/mysql에 데이터 파일을 저장하므로, 모든 데이터가 볼륨에 저장된다.
3.3. 데이터 영속성 확인 실습
Step 1: 데이터 생성
# MySQL 컨테이너 실행
docker run -d \\
--name mysql-test \\
-v mysql-data:/var/lib/mysql \\
-e MYSQL_ROOT_PASSWORD=root \\
mysql:8.0
# 컨테이너에 접속하여 데이터베이스 생성
docker exec -it mysql-test mysql -p
# (비밀번호: root)
mysql> CREATE DATABASE myapp;
mysql> SHOW DATABASES;
mysql> exit
Step 2: 컨테이너 삭제
docker rm -f mysql-test
Step 3: 새 컨테이너 실행 (같은 볼륨 사용)
docker run -d \\
--name mysql-test-new \\
-v mysql-data:/var/lib/mysql \\
-e MYSQL_ROOT_PASSWORD=root \\
mysql:8.0
# 데이터 확인
docker exec -it mysql-test-new mysql -p
mysql> SHOW DATABASES;
# myapp 데이터베이스가 그대로 존재함을 확인!
컨테이너는 새로 실행했지만, 이전에 생성했던 myapp 데이터베이스가 그대로 남아 있다. 볼륨에 데이터가 영구 저장되었기 때문이다.
4. 바인드 마운트 (Bind Mount)
4.1. 바인드 마운트 사용법
# 호스트에 디렉토리 생성
mkdir -p /home/user/nginx-html
# 간단한 HTML 파일 생성
echo "<h1>Hello from Bind Mount</h1>" > /home/user/nginx-html/index.html
# 바인드 마운트로 컨테이너 실행
docker run -d \\
--name nginx-bind \\
-p 8080:80 \\
-v /home/user/nginx-html:/usr/share/nginx/html \\
nginx
- v /home/user/nginx-html:/usr/share/nginx/html: 호스트의 /home/user/nginx-html를 컨테이너의 웹 루트에 마운트
이제 브라우저에서 localhost:8080에 접속하면 "Hello from Bind Mount" 메시지가 보인다.
4.2. 실시간 반영 확인
# 호스트에서 HTML 파일 수정
echo "<h1>Modified Content</h1>" > /home/user/nginx-html/index.html
브라우저를 새로고침하면 내용이 즉시 바뀐다. 컨테이너를 재시작할 필요 없이 호스트의 파일 변경이 실시간으로 반영된다.
4.3. 개발 환경에서의 활용
바인드 마운트는 개발 환경에서 매우 유용하다.
# 소스 코드 디렉토리에서 컨테이너 실행
cd ~/my-project
docker run -d \\
--name dev-app \\
-p 3000:3000 \\
-v $(pwd):/app \\
-v /app/node_modules \\
node:18 \\
npm run dev
- v $(pwd):/app: 현재 디렉토리를 컨테이너의 /app에 마운트
- v /app/node_modules: 컨테이너 내부의 node_modules는 볼륨으로 별도 관리 (호스트와 충돌 방지)
개발자가 호스트에서 코드를 수정하면, 컨테이너 내부에도 즉시 반영되어 개발 서버가 자동으로 리로드된다.
5. 볼륨 마운트 vs 바인드 마운트
5.1. 명령어에서 구분하기
두 방식 모두 -v 옵션을 사용하지만, 경로 형식으로 구분할 수 있다.
| 방식 | 명령어 예시 | 특징 |
| 볼륨 마운트 | -v my-volume:/data | 볼륨 이름으로 시작 (슬래시 없음) |
| 바인드 마운트 | -v /host/path:/data | 절대 경로로 시작 (슬래시 포함) |
5.2. 언제 무엇을 사용할까?
볼륨 마운트를 사용해야 할 때:
- 데이터베이스 파일처럼 영구 보관이 중요한 경우
- 백업이나 마이그레이션이 필요한 경우
- 여러 컨테이너가 데이터를 공유해야 하는 경우
바인드 마운트를 사용해야 할 때:
- 개발 중 코드 변경 사항을 실시간 반영해야 할 때
- 호스트의 설정 파일을 컨테이너에 적용해야 할 때
- 로그 파일을 호스트에서 직접 확인해야 할 때
6. 실전 예제: MySQL + WordPress
WordPress는 MySQL 데이터베이스가 필요하다. 볼륨을 사용하여 데이터를 영구적으로 저장해보자.
6.1. MySQL 컨테이너
# MySQL 데이터용 볼륨 생성
docker volume create wordpress-db-data
# MySQL 컨테이너 실행
docker run -d \\
--name wordpress-db \\
-v wordpress-db-data:/var/lib/mysql \\
-e MYSQL_ROOT_PASSWORD=rootpassword \\
-e MYSQL_DATABASE=wordpress \\
-e MYSQL_USER=wpuser \\
-e MYSQL_PASSWORD=wppassword \\
mysql:8.0
6.2. WordPress 컨테이너
# WordPress 파일용 볼륨 생성 (또는 바인드 마운트)
docker volume create wordpress-data
# WordPress 컨테이너 실행
docker run -d \\
--name wordpress-app \\
-p 8080:80 \\
-v wordpress-data:/var/www/html \\
-e WORDPRESS_DB_HOST=wordpress-db:3306 \\
-e WORDPRESS_DB_USER=wpuser \\
-e WORDPRESS_DB_PASSWORD=wppassword \\
-e WORDPRESS_DB_NAME=wordpress \\
--link wordpress-db \\
wordpress:latest
6.3. 데이터 영속성 확인
- 브라우저에서 localhost:8080 접속하여 WordPress 설치 완료
- 글을 몇 개 작성한다.
- 컨테이너를 모두 삭제한다.
docker rm -f wordpress-app wordpress-db - bash
- 위와 동일한 명령어로 컨테이너를 다시 실행한다.
- 브라우저에서 접속하면 이전에 작성했던 글이 그대로 남아 있다.
7. 고급: 컨테이너 간 데이터 공유
7.1. 같은 볼륨을 여러 컨테이너에 마운트
# 공유 볼륨 생성
docker volume create shared-data
# 첫 번째 컨테이너
docker run -d --name app1 -v shared-data:/data ubuntu bash -c "while true; do echo hello >> /data/log.txt; sleep 5; done"
# 두 번째 컨테이너
docker run -d --name app2 -v shared-data:/data ubuntu bash -c "tail -f /data/log.txt"
app1이 생성한 로그를 app2가 실시간으로 확인할 수 있다.
7.2. 볼륨 컨테이너 패턴 (deprecated)
예전에는 데이터 전용 컨테이너를 만들어 사용하기도 했지만, 요즘은 볼륨을 직접 사용하는 것이 권장된다.
# 데이터 전용 컨테이너 (현재는 거의 사용 안 함)
docker create -v /data --name data-container ubuntu
# 다른 컨테이너에서 --volumes-from으로 마운트
docker run -d --volumes-from data-container --name app nginx
8. 볼륨 관리 팁
8.1. 볼륨 백업과 복원
# 볼륨 백업
docker run --rm -v mysql-data:/data -v $(pwd):/backup ubuntu tar czf /backup/mysql-backup.tar.gz -C /data .
# 볼륨 복원
docker run --rm -v mysql-data:/data -v $(pwd):/backup ubuntu tar xzf /backup/mysql-backup.tar.gz -C /data
8.2. 볼륨 용량 확인
볼륨의 실제 위치에서 직접 확인할 수 있다.
# 볼륨 경로 확인
docker volume inspect mysql-data
# 실제 디스크 사용량 확인 (Linux)
sudo du -sh /var/lib/docker/volumes/mysql-data/_data
9. 정리
볼륨 관련 주요 명령어
| 명령어 | 설명 |
| docker volume create [이름] | 볼륨 생성 |
| docker volume ls | 볼륨 목록 확인 |
| docker volume inspect [이름] | 볼륨 상세 정보 |
| docker volume rm [이름] | 볼륨 삭제 |
| docker volume prune | 사용하지 않는 볼륨 일괄 삭제 |
마운트 방식 비교
| 특징 | 볼륨 마운트 | 바인드 마운트 |
| 관리 주체 | 도커 | 사용자 |
| 위치 | /var/lib/docker/volumes/ | 사용자 지정 경로 |
| 백업/복원 | docker 명령어로 가능 | 직접 파일 복사 |
| 성능 | 최적화됨 | 파일시스템에 의존 |
| 사용처 | 운영 환경, 데이터베이스 | 개발 환경, 설정 파일 |
10. 마치며
이번 포스팅에서는 컨테이너의 가장 큰 약점인 데이터 휘발성을 해결하는 방법인 볼륨에 대해 알아보았다.
- 볼륨 마운트: 도커가 관리하는 영역에 데이터 저장
- 바인드 마운트: 호스트의 특정 경로를 직접 연결
- 데이터베이스처럼 중요한 데이터는 반드시 볼륨에 저장해야 함
- 개발 환경에서는 바인드 마운트로 실시간 코드 반영 가능
다음 포스팅에서는 여러 컨테이너가 서로 통신하는 방법, 즉 Docker Network에 대해 알아보겠다.
'Docker' 카테고리의 다른 글
| [ADVANCED #1] 여러 컨테이너 한 번에 관리하기: Docker Compose (0) | 2025.06.01 |
|---|---|
| [BASIC #6] 컨테이너 간 통신: Docker Network 이해하기 (0) | 2025.06.01 |
| [BASIC #4] 나만의 이미지 만들기: Dockerfile 완전 정복 (0) | 2025.05.31 |
| [BASIC #3] 밀키트 비유로 완벽 이해하는 도커 이미지와 컨테이너 (0) | 2025.05.31 |
| [BASIC #2] 도커 설치부터 첫 컨테이너 실행까지 (Hello World 실습) (0) | 2025.05.31 |
