🐳

Hướng dẫn Backup & Restore Docker Volume

Sao lưu và phục hồi dữ liệu volume cho DCP_PRODUCTION · GREAT_LOTUS

📁 B00_Docker_Volume_DailyBackup/
Chạy nhanh
$ ./backup_all_docker_volumes.sh

Sao lưu toàn bộ Docker volume thành file .tar.gz. Đã được cron chạy tự động 01:00 mỗi ngày — bình thường anh không cần chạy tay.

Nó làm gì tự động hàng ngày

  1. Xoá backup cũ hơn 7 ngày
    Giữ lại đúng 7 bản gần nhất để tiết kiệm đĩa.
  2. Dọn ảnh cứu hộ tạm quá hạn
    Xoá thư mục trong temp_restore_snapshot/ già hơn 24 giờ (do lệnh restore tạo ra).
  3. Nén từng volume
    Duyệt qua mọi volume, đóng gói mỗi cái thành một .tar.gz riêng bằng container alpine.
  4. In kết quả từng volume
    ✔ Success hoặc ✘ Failed cho mỗi volume.

Kết quả trông như thế nào

$ ./backup_all_docker_volumes.sh
Starting Docker volume backup at 20260717_010001
Backup location: /disk2/docker/backup_volumes
--------------------------------------
Cleaning restore snapshots older than 24h in: temp_restore_snapshot
  - removing expired snapshot: 20260715_203045
--------------------------------------
Backing up volume: dcp_production_mysql_data
✔ Success: dcp_production_mysql_data
--------------------------------------
Backing up volume: dcp_production_n8n_volume
✔ Success: dcp_production_n8n_volume
--------------------------------------
All volumes backed up.

Chi tiết cần biết

MụcGiá trị
Nơi lưu backup/disk2/docker/backup_volumes/ (qua symlink backup_volumes)
Tên file<tên_volume>_<YYYYMMDD>_<HHMMSS>.tar.gz
Lịch chạyCron · 01:00 mỗi ngày
Số bản giữ lại7 ngày gần nhất (cũ hơn tự xoá)
Dọn ảnh cứu hộThư mục temp_restore_snapshot/ quá 24h bị xoá
💡 Vì sao có bước dọn ảnh cứu hộ? Mỗi lần anh chạy restore, script phục hồi tự chụp một bản "cứu hộ" của trạng thái hiện tại vào temp_restore_snapshot/ để anh có thể quay lại nếu lỡ. Những bản này chỉ cần sống ~1 ngày, nên chính script backup này dọn giúp — hai vòng đời tách bạch, không lẫn với backup 7 ngày.
⚠ Chạy tay khi nào? Trước khi làm việc gì rủi ro (nâng cấp lớn, đổi cấu hình database), anh có thể chạy ./backup_all_docker_volumes.sh để có ngay một bản mới, thay vì chờ 01:00.
Chạy nhanh
$ ./restore_docker_volumes.sh

Script hỏi anh từng bước — không cần nhớ tham số. Chọn nguồn → chọn thời điểm → chọn volume → gõ RESTORE để xác nhận.

🛑 Quy tắc vàng: tắt container trước Script từ chối phục hồi volume đang được container chạy sử dụng — vì ghi đè volume "sống" sẽ làm hỏng dữ liệu. Anh phải tự docker stop <container> trước, rồi chạy lại. Script cố ý không tự tắt hộ để khỏi kéo sập nhầm dịch vụ khác.

Năm bước của lệnh restore

  1. Bước 0 — Chọn nguồn
    1) Daily snapshot (backup hàng ngày, giữ 7 ngày)  hay  2) Ảnh cứu hộ tạm (chụp trước mỗi lần restore, tự xoá sau 24h).
  2. Bước 1 — Chọn thời điểm
    Danh sách các mốc ngày (hoặc các ảnh cứu hộ) hiện ra kèm số thứ tự. Nhập số của mốc muốn về.
  3. Bước 2 — Chọn volume
    Danh sách volume của mốc đó. Nhập số — có thể nhiều volume cùng lúc (xem cách nhập bên dưới).
  4. Bước 3 — Xác nhận bằng TÊN
    Màn hình liệt kê rõ tên volume sẽ ghi đè (không phải số). Gõ RESTORE để tiếp tục, gõ thứ khác để huỷ.
  5. Bước 4 — Chụp cứu hộ → phục hồi
    Script tự chụp bản cứu hộ (có thanh tiến trình) → xoá sạch volume → giải nén bản backup vào. Nếu chụp lỗi, dừng ngay, không đụng volume.

Cách nhập ở Bước 2 (chọn volume)

4 một volume số 4
3,9 volume 3 và 9
1-5 từ 1 đến 5
1-3,7 kết hợp
all tất cả

Ví dụ: phục hồi n8n về hôm qua (kịch bản "lỡ tay")

$ docker stop lotus_n8n && ./restore_docker_volumes.sh
▸ Bước 0/4 — Phục hồi từ nguồn nào?
  ┌────────────────────────────────────────────────┐
    1  📅  DAILY SNAPSHOT  · giữ 7 ngày           
    2TEMPORARY RESTORE SNAPSHOT · 24h    
  └────────────────────────────────────────────────┘
  ❯ Chọn nguồn [1-2]: 1

▸ Bước 1/4 — Chọn thời điểm phục hồi
   #   NGÀY BACKUP          TUỔI       VOLUME
   1   2026-07-17  01:00    hôm nay     17     ← mới nhất
   2   2026-07-16  01:00    1 ngày      17
  ❯ Chọn ngày [1-8]: 2

▸ Bước 2/4 — Chọn volume · daily 2026-07-16
   #   VOLUME                          TRẠNG THÁI
   5   dcp_production_n8n_volume       ○ rảnh
   4   dcp_production_mysql_data       ● lotus_mysql  (sẽ bị chặn)
  ❯ Chọn volume (vd: 3,9 · 1-5 · all): 5

▸ Bước 3/4 — Xác nhận
  ┌────────────────────────────────────────────────┐
    ⚠  HÀNH ĐỘNG NÀY GHI ĐÈ DỮ LIỆU HIỆN TẠI       
  └────────────────────────────────────────────────┘
     Phục hồi từ :  daily 2026-07-16  01:00
         dcp_production_n8n_volume
  ❯ Gõ RESTORE để tiếp tục: RESTORE

▸ Bước 4/4 — Đang chụp ảnh cứu hộ…
    [1/1]    dcp_production_n8n_volume   88 M   hoàn tất
  ┌────────────────────────────────────────────────┐
   ✔ Nếu lỗi, quay về CŨ: nguồn 2 → 20260717_...  
  └────────────────────────────────────────────────┘
  ✔  Hoàn tất: 1/1 volume đã phục hồi
  Đừng quên:  docker start lotus_n8n
docker stop restore volume docker start kiểm tra

Bảng trạng thái volume ở Bước 2

Ký hiệuÝ nghĩa
○ rảnhKhông container nào dùng → an toàn phục hồi.
● lotus_xĐang bị container chạy dùng → sẽ bị chặn, phải stop trước.
○ chưa tồn tạiVolume chưa có → script tự tạo rồi phục hồi.
🛟 Luôn có đường lùi Trước khi ghi đè, script tự chụp ảnh cứu hộ của trạng thái hiện tại. Nếu phục hồi xong thấy vẫn sai, chạy lại script → chọn nguồn 2 (temporary snapshot) → chọn ảnh vừa chụp để quay về đúng như trước. Ảnh cứu hộ sống tối thiểu 24h.
🛑 Khi gặp màn hình "BỊ CHẶN" Nếu chọn nhầm volume đang chạy, script in ra đúng lệnh cần chạy và thoát:
✘ BỊ CHẶN — dcp_production_mysql_data
đang dùng bởi: lotus_mysql
docker stop lotus_mysql
Chạy lệnh đó, rồi chạy lại restore.

Tham số nâng cao tuỳ chọn

CờCông dụng
--dry-runDiễn tập: in ra mọi việc sẽ làm nhưng không đụng volume nào. Dùng để xem trước cho chắc.
--to <tên>Giải nén sang một volume mới thay vì ghi đè volume gốc — để soi dữ liệu trước rồi mới quyết định. Chỉ dùng với 1 volume.
--yes / -yBỏ qua màn xác nhận (cho kịch bản tự động hoá). Dùng cẩn thận.
--no-colorTắt màu ANSI. Màu vốn tự tắt khi ghi ra file/pipe, nên hiếm khi cần.
-h / --helpXem trợ giúp ngắn gọn.
💡 Mẹo an toàn nhất Lần đầu phục hồi, chạy kèm --dry-run để xem chính xác script sẽ làm gì mà không thay đổi gì cả. Yên tâm rồi mới chạy thật.