“이제와서 시작하는 Docker 마스터하기” 컨테이너는 기본적으로 임시적(ephemeral)입니다. 컨테이너가 삭제되면 내부의 데이터도 함께 사라집니다. Docker 볼륨을 사용하면 데이터를 영구적으로 저장하고 관리할 수 있습니다.
왜 볼륨이 필요한가?
컨테이너의 데이터 문제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # MySQL 컨테이너 실행
docker run -d --name mydb -e MYSQL_ROOT_PASSWORD=secret mysql:5.7
# 데이터베이스에 데이터 추가
docker exec -it mydb mysql -p
# CREATE DATABASE testdb;
# exit
# 컨테이너 삭제
docker rm -f mydb
# 새 컨테이너 실행
docker run -d --name mydb -e MYSQL_ROOT_PASSWORD=secret mysql:5.7
# 데이터가 사라졌습니다!
docker exec -it mydb mysql -p -e "SHOW DATABASES;"
|
Docker 스토리지 옵션
Docker는 세 가지 데이터 저장 방식을 제공합니다:
- 볼륨(Volumes): Docker가 관리하는 스토리지
- 바인드 마운트(Bind Mounts): 호스트 파일시스템 직접 연결
- tmpfs 마운트: 메모리에 임시 저장
볼륨(Volumes)
볼륨 생성 및 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 볼륨 생성
docker volume create my-volume
# 볼륨 목록 확인
docker volume ls
# 볼륨 상세 정보
docker volume inspect my-volume
# 볼륨 삭제
docker volume rm my-volume
# 사용하지 않는 볼륨 모두 삭제
docker volume prune
|
볼륨 사용하기
1
2
3
4
5
6
7
8
9
| # 볼륨을 마운트하여 컨테이너 실행
docker run -d \
--name mysql-db \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:5.7
# 볼륨 위치 확인
docker volume inspect mysql-data
|
익명 볼륨
1
2
3
4
5
6
7
8
| # 이름 없이 볼륨 생성 (익명 볼륨)
docker run -d \
--name web \
-v /usr/share/nginx/html \
nginx
# 익명 볼륨 확인
docker inspect web | grep -A 10 Mounts
|
바인드 마운트(Bind Mounts)
호스트의 특정 디렉토리를 컨테이너에 마운트합니다:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 현재 디렉토리를 마운트
docker run -d \
--name web-dev \
-v $(pwd)/html:/usr/share/nginx/html \
-p 8080:80 \
nginx
# Windows에서는
docker run -d \
--name web-dev \
-v ${PWD}/html:/usr/share/nginx/html \
-p 8080:80 \
nginx
|
읽기 전용 마운트
1
2
3
4
5
| # 읽기 전용으로 마운트
docker run -d \
--name web-ro \
-v $(pwd)/config:/etc/nginx/conf.d:ro \
nginx
|
실습: WordPress와 MySQL 데이터 영속성
1. 네트워크 생성
1
| docker network create wordpress-net
|
2. MySQL with Volume
1
2
3
4
5
6
7
8
9
10
11
12
13
| # MySQL 볼륨 생성
docker volume create mysql-data
# MySQL 실행
docker run -d \
--name wordpress-db \
--network wordpress-net \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpass \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wordpress \
-e MYSQL_PASSWORD=wordpass \
mysql:5.7
|
3. WordPress with Volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # WordPress 볼륨 생성
docker volume create wordpress-data
# WordPress 실행
docker run -d \
--name wordpress-app \
--network wordpress-net \
-v wordpress-data:/var/www/html \
-p 8080:80 \
-e WORDPRESS_DB_HOST=wordpress-db \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpass \
-e WORDPRESS_DB_NAME=wordpress \
wordpress:latest
|
4. 데이터 영속성 테스트
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # WordPress 설정 후 컨테이너 삭제
docker rm -f wordpress-app wordpress-db
# 동일한 볼륨으로 다시 실행
docker run -d \
--name wordpress-db \
--network wordpress-net \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=rootpass \
mysql:5.7
docker run -d \
--name wordpress-app \
--network wordpress-net \
-v wordpress-data:/var/www/html \
-p 8080:80 \
-e WORDPRESS_DB_HOST=wordpress-db \
-e WORDPRESS_DB_USER=wordpress \
-e WORDPRESS_DB_PASSWORD=wordpass \
-e WORDPRESS_DB_NAME=wordpress \
wordpress:latest
# 데이터가 유지됨!
|
볼륨 백업과 복원
볼륨 백업
1
2
3
4
5
6
| # 볼륨을 tar 파일로 백업
docker run --rm \
-v mysql-data:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/mysql-backup.tar.gz -C /data .
|
볼륨 복원
1
2
3
4
5
6
7
8
9
| # 새 볼륨 생성
docker volume create mysql-data-restored
# 백업에서 복원
docker run --rm \
-v mysql-data-restored:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/mysql-backup.tar.gz -C /data
|
볼륨 드라이버
로컬 드라이버 옵션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # 특정 디바이스 사용
docker volume create \
--driver local \
--opt type=none \
--opt device=/mnt/data \
--opt o=bind \
my-local-volume
# NFS 볼륨 (NFSv4 예시)
docker service create -d \
--name nfs-service \
--mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
nginx:latest
# CIFS/Samba 볼륨 (2025년 최신)
docker volume create \
--driver local \
--opt type=cifs \
--opt device=//server.example.com/share \
--opt o=addr=server.example.com,username=user,password=pass,file_mode=0777,dir_mode=0777 \
cifs-volume
# 블록 디바이스 마운트
docker run \
--mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4' \
ubuntu
|
실습: 개발 환경 구성
1. Node.js 개발 환경
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| # 프로젝트 디렉토리 생성
mkdir node-dev && cd node-dev
# package.json 생성
cat > package.json << EOF
{
"name": "node-dev",
"version": "1.0.0",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.18.0"
},
"devDependencies": {
"nodemon": "^2.0.0"
}
}
EOF
# app.js 생성
cat > app.js << EOF
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello from Docker Dev Environment!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
EOF
# Dockerfile
cat > Dockerfile << EOF
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
EOF
|
2. 개발 모드로 실행
1
2
3
4
5
6
7
8
| # 소스 코드를 바인드 마운트
docker run -d \
--name node-dev \
-v $(pwd):/app \
-v /app/node_modules \
-p 3000:3000 \
node:16-alpine \
sh -c "cd /app && npm install && npm run dev"
|
볼륨 공유
여러 컨테이너에서 볼륨 공유
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # 공유 볼륨 생성
docker volume create shared-data
# 첫 번째 컨테이너
docker run -d \
--name writer \
-v shared-data:/data \
alpine \
sh -c "while true; do date >> /data/log.txt; sleep 5; done"
# 두 번째 컨테이너
docker run -d \
--name reader \
-v shared-data:/data \
alpine \
sh -c "tail -f /data/log.txt"
# 로그 확인
docker logs reader
|
tmpfs 마운트
메모리에 임시 데이터 저장:
1
2
3
4
5
6
7
8
9
| # tmpfs 마운트 사용
docker run -d \
--name tmp-test \
--tmpfs /tmp:rw,size=100m \
alpine \
sh -c "dd if=/dev/zero of=/tmp/test bs=1M count=50 && sleep 1000"
# 메모리 사용량 확인
docker stats tmp-test
|
볼륨 베스트 프랙티스
1. 명명된 볼륨 사용
1
2
3
4
5
| # 좋은 예: 명명된 볼륨
docker run -v mysql-data:/var/lib/mysql mysql
# 피해야 할 예: 익명 볼륨
docker run -v /var/lib/mysql mysql
|
2. 볼륨 라벨 사용
1
2
3
4
5
6
7
8
| # 라벨로 볼륨 관리
docker volume create \
--label project=myapp \
--label env=production \
myapp-data
# 라벨로 필터링
docker volume ls --filter label=project=myapp
|
3. 정기적인 백업
1
2
3
4
5
6
7
8
9
10
11
12
| # 백업 스크립트 예시
#!/bin/bash
BACKUP_DIR="/backup/volumes"
DATE=$(date +%Y%m%d_%H%M%S)
for volume in $(docker volume ls -q); do
docker run --rm \
-v $volume:/data \
-v $BACKUP_DIR:/backup \
alpine \
tar czf /backup/${volume}_${DATE}.tar.gz -C /data .
done
|
문제 해결
권한 문제
1
2
3
4
5
6
7
8
9
| # 사용자 ID 확인
docker run --rm alpine id
# 권한 설정
docker run -d \
--name web \
-v $(pwd)/data:/data \
--user $(id -u):$(id -g) \
nginx
|
볼륨 정리
1
2
3
4
5
6
7
8
| # 사용하지 않는 볼륨 확인
docker volume ls -f dangling=true
# 안전하게 정리
docker volume prune
# 강제 정리 (주의!)
docker volume prune -f
|
마무리
Docker 볼륨을 사용하면 컨테이너의 생명주기와 독립적으로 데이터를 관리할 수 있습니다. 데이터베이스, 파일 업로드, 설정 파일 등 영구 보존이 필요한 모든 데이터에 볼륨을 활용하세요. 다음 편에서는 여러 컨테이너를 쉽게 관리할 수 있는 Docker Compose에 대해 알아보겠습니다.
다음 편 예고
- Docker Compose 소개
- docker-compose.yml 작성법
- 멀티 컨테이너 오케스트레이션
- 환경별 설정 관리
복잡한 애플리케이션도 간단하게 관리하는 방법을 배워봅시다!
📚 Docker 마스터하기 시리즈
🐳 기초편 (입문자용 - 5편)
- Docker란 무엇인가?
- Docker 설치 및 환경 설정
- 첫 번째 컨테이너 실행하기
- Docker 이미지 이해하기
- Dockerfile 작성하기
💼 실전편 (중급자용 - 6편)
- Docker 네트워크 기초
- Docker 볼륨과 데이터 관리 ← 현재 글
- Docker Compose 입문
- 멀티 컨테이너 애플리케이션
- Docker Hub 활용하기
- Docker 보안 베스트 프랙티스
🚀 고급편 (전문가용 - 9편)
- Docker 로그와 모니터링
- Docker로 Node.js 애플리케이션 배포
- Docker로 Python 애플리케이션 배포
- Docker로 데이터베이스 운영
- Docker 이미지 최적화
- Docker와 CI/CD
- Docker Swarm 기초
- 문제 해결과 트러블슈팅
- Docker 생태계와 미래