Virtualization

Quản lý Docker volume và backup dữ liệu container

Container Docker trong suốt theo định nghĩa, một khi xóa container, toàn bộ dữ liệu bên trong biến mất nếu bạn không mount volume ra ngoài. Chạy docker rm -f nhầm container database hay ứng dụng đang chạy production, mất dữ liệu chỉ trong tích tắc. Bài này viết cho sysadmin muốn hiểu rõ cơ chế volume trong Docker và có một quy trình backup/restore dữ liệu container chắc chắn, có thể chạy tự động trên thuê VPS Linux của bạn.

  • Ba kiểu mount trong Docker: bind mount, volume, tmpfs, mỗi loại dùng cho tình huống khác nhau.
  • Volume là gì? Vùng lưu trữ do Docker quản lý, độc lập với vòng đời container, backup dễ nhất.
  • Backup thế nào? Dùng lệnh docker run --rm với mount volume để tar dữ liệu ra ngoài.
  • Restore nhanh: Giải nén tar vào volume cũ rồi gắn lại container.

Yêu cầu trước khi bắt đầu

  • VPS chạy Ubuntu 24.04 LTS hoặc Debian 12, đã cài Docker engine và Docker Compose v2 (docker compose, không dùng docker-compose).
  • User sudo non-root hoặc root.
  • Có sẵn một container đang chạy có volume để thao tác thử.

Vì sao cần quản lý Docker volume riêng?

Khi bạn chạy MySQL, PostgreSQL, N8N, Grafana, hoặc bất kỳ ứng dụng nào có trạng thái (stateful), dữ liệu của chúng nằm trong volume hoặc bind mount. Nếu container bị xóa và không mount lại đúng volume cũ, dữ liệu coi như mất. Volume do Docker quản lý có lợi thế: dễ backup, dễ di chuyển giữa các host, và không phụ thuộc vào cấu trúc thư mục của host. Bind mount thì phụ thuộc vào đường dẫn rất cao trên host, khi chuyển máy phải mount lại đúng thư mục.

Mình từng thấy nhiều người mới dùng Docker chạy docker-compose down rồi up -d lại mà không để ý volume đã bị xóa theo docker-compose down -v. Container mới chạy lên sạch trơn, không còn dữ liệu cũ. Với production, quy tắc vàng: hiếm khi dùng -v với down trừ khi bạn chắc chắn đã backup.

Bước 1 - Phân biệt bind mount, volume và tmpfs

Trước khi nói đến backup, phải hiểu rõ ba kiểu mount trong Docker vì cách backup của mỗi loại khác nhau.

Kiểu mountQuản lý bởiĐường dẫn trên hostDễ backup
VolumeDocker/var/lib/docker/volumes/<name>/_dataCao (dùng lệnh Docker)
Bind mountNgười dùngThư mục bất kỳ (vd /data/mysql)Thấp (copy thủ công)
tmpfsRAMKhông cóKhông cần (dữ liệu tạm)

Volume là lựa chọn khuyên dùng cho dữ liệu cần bền vì Docker quản lý và bạn có thể backup bằng lệnh docker run --rm -v. Bind mount thường dùng khi bạn muốn chỉnh sửa file cấu hình từ host (vd mount file nginx.conf), backup lúc đó là backup thư mục thông thường. tmpfs dùng cho dữ liệu tạm không cần giữ (vd session, cache), không cần backup.

Lệnh kiểm tra các volume đang có trên hệ thống:

docker volume ls

Output mong đợi (tên volume tùy vào những gì bạn đã tạo):

DRIVER    VOLUME NAME
local     n8n_data
local     postgres_data
local     portainer_data

Lấy thông tin chi tiết một volume

docker volume inspect n8n_data

Lệnh này trả về đường dẫn thật trên host (Mountpoint), driver, và label. Biết Mountpoint bạn có thể ls vào xem thử.

Bước 2 - Backup Docker volume bằng lệnh tar

Cách chuẩn để backup một volume Docker là dùng container tạm thời mount volume đó và thư mục đích, rồi chạy tar. Cách này không cần dừng container nguồn (nếu bạn chấp nhận rủi ro dữ liệu thay đổi trong lúc backup) hoặc bạn nên dừng container vài giây để đảm bảo snapshot nhất quán.

Backup mà không dừng container (backup nóng)

Dùng cho dữ liệu không yêu cầu nhất quán rất cao tại thời điểm chụp (vd log, file tĩnh):

docker run --rm \
  -v n8n_data:/source:ro \
  -v /backup/docker:/backup \
  alpine \
  tar czf /backup/n8n_data-$(date +%Y%m%d_%H%M%S).tar.gz -C /source .

Giải thích: container từ image alpine chạy lên, mount volume n8n_data ở chế độ read-only (:ro), mount thư mục backup trên host (/backup/docker) vào /backup trong container, rồi tar toàn bộ nội dung của volume ra file nén với timestamp.

Backup an toàn: dừng container trước khi chụp

Với database (MySQL, PostgreSQL), cách an toàn nhất là dừng container trước, backup, rồi bật lại. Hoặc dùng lệnh dump riêng của database (mysqldump, pg_dump) nhưng vẫn nên có backup volume để phòng trường hợp dump hỏng.

docker stop n8n
docker run --rm \
  -v n8n_data:/source \
  -v /backup/docker:/backup \
  alpine \
  tar czf /backup/n8n_data-$(date +%Y%m%d_%H%M%S).tar.gz -C /source .
docker start n8n

Kiểm tra file backup đã tạo:

ls -lh /backup/docker/

Output:

-rw-r--r-- 1 root root 2.3M Apr  7 10:15 n8n_data-20260407_101532.tar.gz

Bước 3 - Restore Docker volume từ file tar

Restore cũng dùng container tạm nhưng ngược lại: giải nén tar vào volume trống. Trước khi restore, đảm bảo container đã dừng và volume cũ đã được xóa sạch (hoặc bạn restore sang volume mới).

Cách 1: Restore vào volume cũ (xóa dữ liệu cũ trước)

Khi container bị hỏng, bạn muốn đưa volume về trạng thái đã backup:

docker stop n8n
docker rm n8n   # xóa container, không xóa volume
docker volume rm n8n_data   # xóa volume cũ để tạo lại sạch
docker volume create n8n_data
docker run --rm \
  -v n8n_data:/target \
  -v /backup/docker:/backup \
  alpine \
  tar xzf /backup/n8n_data-20260407_101532.tar.gz -C /target
# Sau đó chạy lại container với cùng volume

Lưu ý: xóa volume cũ bằng docker volume rm là hành động không thể undo, hãy chắc chắn bạn đã có backup file tar.

Cách 2: Restore vào volume mới (an toàn hơn)

Trong trường hợp container còn chạy tốt nhưng bạn muốn thử restore sang volume khác để kiểm tra trước khi chuyển đổi:

docker volume create n8n_data_restored
docker run --rm \
  -v n8n_data_restored:/target \
  -v /backup/docker:/backup \
  alpine \
  tar xzf /backup/n8n_data-20260407_101532.tar.gz -C /target

Xong rồi mount volume mới vào container bằng cách sửa docker-compose.yml hoặc chạy container mới.

Bước 4 - Script backup tự động với cron/systemd timer

Backup thủ công mỗi lần thì sẽ quên. Tự động hóa bằng cron hoặc systemd timer là bước bắt buộc cho bất kỳ VPS nào chạy container production. Dưới đây là script backup toàn bộ volume trên máy, lưu vào thư mục /backup/docker và giữ 7 ngày gần nhất.

#!/bin/bash
# /usr/local/bin/docker-volume-backup.sh
BACKUP_DIR="/backup/docker"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7

mkdir -p "$BACKUP_DIR"

# Lấy danh sách volume (chỉ volume named, bỏ anonymous)
VOLUMES=$(docker volume ls --format '{{.Name}}' | grep -v '^[0-9a-f]\{64\}$')

for VOL in $VOLUMES; do
  echo "Backing up volume: $VOL"
  docker run --rm \
    -v "$VOL":/source:ro \
    -v "$BACKUP_DIR":/backup \
    alpine \
    tar czf "/backup/${VOL}-${DATE}.tar.gz" -C /source .
done

# Xóa backup cũ hơn RETENTION_DAYS
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed at $(date)"

Cấp quyền thực thi và chạy thử:

chmod +x /usr/local/bin/docker-volume-backup.sh
sudo /usr/local/bin/docker-volume-backup.sh

Thêm vào cron (chạy mỗi ngày lúc 3h sáng)

sudo crontab -e

Thêm dòng:

0 3 * * * /usr/local/bin/docker-volume-backup.sh >> /var/log/docker-backup.log 2>&1

Kiểm tra log sau vài lần chạy:

tail -f /var/log/docker-backup.log

Bước 5 - Backup toàn bộ docker-compose stack (volume + cấu hình)

Chỉ backup volume là chưa đủ. Khi gặp sự cố thực sự (hỏng OS, phải cài lại VPS từ đầu), bạn cần cả file docker-compose.yml, file .env, và các thư mục bind mount. Quy trình backup đầy đủ cho một stack:

  1. Backup docker-compose.yml và .env: đơn giản là copy toàn bộ thư mục project.
  2. Backup volume: dùng script ở bước 4.
  3. Backup bind mount: chạy tar trực tiếp trên host cho các thư mục bind.
#!/bin/bash
# /usr/local/bin/backup-n8n-stack.sh
STACK_DIR="/opt/n8n"
BACKUP_DIR="/backup/n8n-stack"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# Backup compose files
tar czf "$BACKUP_DIR/n8n-compose-${DATE}.tar.gz" -C "$STACK_DIR" docker-compose.yml .env

# Backup volume
docker run --rm \
  -v n8n_data:/source:ro \
  -v "$BACKUP_DIR":/backup \
  alpine \
  tar czf "/backup/n8n-volume-${DATE}.tar.gz" -C /source .

# Backup bind mount nếu có
[ -d "$STACK_DIR/data" ] && tar czf "$BACKUP_DIR/n8n-bind-${DATE}.tar.gz" -C "$STACK_DIR/data" .

echo "Stack backup done: $BACKUP_DIR"

Xử lý lỗi thường gặp

Lỗi "docker: no space left on device" khi tạo volume

Nguyên nhân: partition chứa /var/lib/docker đầy. Kiểm tra bằng df -h /var/lib/docker. Giải pháp: xóa volume không dùng (docker volume prune) hoặc di chuyển thư mục Docker sang partition khác.

Lỗi permission denied khi backup volume của container chạy với user khác root

Khi container chạy với user ID không phải 0 (root), file trong volume có owner là user đó. Container tạm alpine chạy mặc định với root, vẫn đọc được, nhưng khi restore, owner file giữ nguyên. Nếu restore vào volume mới và chạy container với user không phải root, có thể không đọc được file. Giải pháp: thêm option --userns=host nếu dùng user namespace remapping, hoặc dùng container backup chạy cùng user ID với container gốc.

Lỗi "volume is in use" không xóa được

Không thể xóa volume khi có container đang dùng nó. Phải dừng và xóa container trước:

docker ps -a --filter volume=n8n_data
docker stop <container_id>
docker rm <container_id>
docker volume rm n8n_data

Câu hỏi thường gặp

Có thể backup Docker volume khi container đang chạy không?

Có, nếu dữ liệu không yêu cầu nhất quán nghiêm ngặt (file tĩnh, log). Với database, nên dùng dump công cụ chuyên dụng (mysqldump, pg_dump) hoặc dừng container vài giây để chụp snapshot an toàn.

Backup Docker volume có nén dung lượng giảm bao nhiêu?

Tùy vào loại dữ liệu. Dữ liệu text (database, log, JSON) nén tốt, thường giảm 60-80%. File nhị phân (ảnh, video) hầu như không nén được. Dùng lệnh tar czf để nén gzip tự động.

Bind mount có cần backup riêng không?

Có, bind mount là thư mục thường trên host, không do Docker quản lý, nên backup bằng lệnh tar/cp thông thường. Đừng quên thêm bind mount vào script backup của bạn.

Docker volume backup có thể khôi phục lên máy chủ khác không?

Được, miễn là máy chủ đó có Docker và bạn tạo volume cùng tên (hoặc mount volume mới). Nếu volume tên khác, khi chạy container phải mount đúng tên volume mới. File tar là portable.

Có nên backup toàn bộ /var/lib/docker không?

Không nên. Thư mục này chứa image layers, container metadata, network config, có thể khôi phục lại bằng cách chạy lại docker compose up và restore volume backup. Backup toàn bộ thư mục sẽ phình to và khó khôi phục từng phần.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.