💾 Sao lưu và rollback trước khi deploy

By Better Wise

Đường lui trước khi bấm deploy

Bài trước bạn đã có feature flag để tắt một tính năng lỗi mà không cần deploy. Nhưng flag chỉ cứu được phần nằm sau flag. Nếu bản deploy làm hỏng API, hỏng migration, hoặc ghi sai dữ liệu, bạn cần thứ khác: một bản sao lưu và một đường rollback đã được tập trước. Nguyên tắc tôi giữ suốt nghề: không ai được bấm deploy khi chưa trả lời được câu "nếu bước này hỏng thì lùi về đâu, bằng lệnh nào, mất bao lâu".

Sau bài này bạn sẽ:

  • Liệt kê được 3 thứ phải sao lưu trước mỗi lần deploy production.
  • Chụp được bản backup có timestamp và biết cách kiểm tra nó dùng được.
  • Phân biệt 3 tầng rollback và chọn đúng tầng cho từng sự cố.
  • Viết được rollback plan 5 dòng và tập chạy nó trên staging.

Sao lưu cái gì trước khi deploy

Đừng sao lưu "cho có". Có đúng ba thứ, thiếu một là rollback sẽ kẹt:

Thứ cần sao lưu Cách làm Cách kiểm tra
Database Dump có timestamp, nén lại Mở được file, restore thử lên staging
Artifact / code Tag Git + giữ image build cũ trong registry Deploy lại đúng tag đó thành công
Cấu hình, secrets Snapshot biến môi trường, version trong secrets manager So sánh được với bản đang chạy

Điểm quan trọng: artifact phải bất biến. Cùng một tag phải ứng với đúng một bản build. Nếu bạn build lại từ cùng một nhánh lúc rollback, bạn đang deploy một bản khác, không phải rollback.

  1. Chạy pg_dump tạo file backup có timestamp, lưu ra ngoài máy production.
  2. Tag phiên bản đang chạy (ví dụ v1.4.2) và xác nhận image cũ vẫn còn trong registry.
  3. Export snapshot cấu hình và secrets đang dùng.
  4. Restore thử file backup lên staging, chạy một smoke test ngắn.
  5. Ghi lại đường dẫn backup vào release note trước khi bấm deploy.

Warning: Backup chưa restore thử thì chỉ là một file nằm đó. Rất nhiều đội phát hiện file dump hỏng đúng lúc đang sự cố.

Bài tập 1 (2 phút). Viết lệnh tạo backup Postgres có timestamp và một lệnh kiểm tra file không rỗng.

Xem đáp án

pg_dump "$DATABASE_URL" -Fc -f "backup_$(date +%Y%m%d_%H%M).dump"
ls -lh backup_*.dump
pg_restore --list backup_20250101_0930.dump | head

-Fc tạo định dạng nén, --list đọc được nghĩa là file không hỏng. Thiếu bước thứ hai thì bạn chưa biết backup có dùng được hay không.

Ba tầng rollback và thời gian mục tiêu

Rollback không phải một nút. Nó là ba tầng, xếp theo tốc độ và mức độ thiệt hại:

  1. Tắt feature flag: vài giây, không deploy, không mất dữ liệu. Luôn thử tầng này trước.
  2. Deploy lại artifact cũ: vài phút. Dùng khi lỗi nằm ngoài phạm vi flag.
  3. Restore database từ backup: chậm nhất, có thể mất dữ liệu phát sinh sau thời điểm backup. Chỉ dùng khi dữ liệu đã hỏng.
flowchart TD
    Fail["🚨 Deploy xong, smoke test đỏ"] --> Flag{"Lỗi nằm sau feature flag?"}
    Flag -->|Có| Off["🎛️ Tắt feature flag"]
    Flag -->|Không| Artifact["📦 Deploy lại artifact cũ"]
    Artifact --> Check{"Smoke test xanh?"}
    Check -->|Có| Done["✅ Ghi log sự cố"]
    Check -->|Không| Restore["🗄️ Restore database từ backup"]
    Off --> Done
    Restore --> Done

Với tầng 2, mục tiêu thực tế là dưới 10 phút, và bạn chỉ đạt được con số đó nếu đã tập một lần trên staging. Với tầng 3, hãy viết sẵn trong runbook: mất bao nhiêu dữ liệu, ai phê duyệt, thông báo cho ai.

Bài tập 2 (3 phút). Chọn tầng rollback cho từng tình huống:

a) Trang thanh toán lỗi, tính năng mới đang nằm sau flag checkout_v2. b) Sau deploy, toàn bộ API trả 500, lỗi không liên quan flag nào. c) Migration vừa chạy xoá mất một cột dữ liệu.

Xem đáp án

a) Tắt checkout_v2. Nhanh nhất, không đụng tới code. b) Deploy lại artifact của phiên bản trước, rồi kiểm tra smoke test. c) Restore database từ backup gần nhất, chấp nhận mất phần dữ liệu phát sinh sau thời điểm đó, và ghi rõ khoảng mất trong báo cáo sự cố.

Viết rollback plan và tập chạy trước

Một rollback plan đủ dùng chỉ cần 5 dòng, nhưng phải cụ thể tới mức người khác làm theo được lúc 2 giờ sáng:

  1. Điều kiện rollback: smoke test đỏ hoặc lỗi ảnh hưởng người dùng, không chờ thêm.
  2. Người bấm: ai có quyền deploy production.
  3. Lệnh cụ thể: tắt flag nào, hoặc deploy lại tag nào.
  4. Nguồn backup: đường dẫn file dump gần nhất và thời điểm tạo.
  5. Kiểm tra sau rollback: chạy lại smoke test, xem log 5 phút.

Sau đó tập chạy trên staging: bấm rollback về bản trước, bấm đồng hồ, ghi lại chỗ nào vướng. Bài tập này rẻ hơn rất nhiều so với lần đầu làm thật trên production.

Bài tập 3 (4 phút). Viết rollback plan 5 dòng cho app bạn đang làm, rồi chạy thử bước "deploy lại tag cũ" trên staging.

Gợi ý đáp án

Điều kiện: smoke test đỏ sau deploy. Người bấm: bạn. Lệnh: deploy --tag v1.4.2 hoặc tắt flag checkout_v2. Backup: backup_20250101_0930.dump trên object storage. Kiểm tra: chạy smoke test 3 bước, xem log lỗi 5 phút, ghi thời gian rollback thực tế vào release note.

Các ý chính của bài:

  • Trước deploy: backup database, giữ artifact cũ, snapshot cấu hình, và restore thử một lần.
  • Rollback theo thứ tự flag → artifact → database, đừng nhảy thẳng xuống tầng nặng nhất.
  • Backup _____ thì chưa được coi là backup.
  • Rollback nhanh nhất là _____, mất vài giây và không cần deploy.
  • Restore database là tầng rollback _____ và có thể mất dữ liệu phát sinh sau thời điểm backup.
  • Artifact phải _____: cùng một tag luôn ứng với đúng một bản build.
  • Không sửa nóng trên production khi đang sự cố, hãy _____ rồi điều tra sau.

Những cái bẫy khiến rollback thất bại

  • Build lại thay vì deploy lại. Build lại từ nhánh cũ không phải rollback, vì đầu ra đã khác. Luôn giữ artifact và deploy đúng tag.
  • Backup nằm cùng chỗ với production. Ổ đĩa hỏng thì mất cả app lẫn backup. Đẩy file dump sang object storage hoặc máy khác.
  • Migration một chiều. Trước khi deploy, tự hỏi migration này lùi được không. Nếu không, hãy backup trước và tách migration ra khỏi lần deploy đó.
  • Không ai dám bấm. Rollback cần người có quyền và đã tập. Ghi tên người đó vào plan.
  • Chờ thêm để xem sao. Smoke test đỏ là đủ điều kiện rollback. Điều tra sau, khi hệ thống đã về trạng thái lành.

Front: Trước khi deploy production phải sao lưu những gì? Back: Database, artifact phiên bản đang chạy, và snapshot cấu hình/secrets.

Front: Khi nào một bản backup được coi là dùng được? Back: Khi đã restore thử thành công ít nhất một lần.

Front: Vì sao tên file backup phải có timestamp? Back: Để chọn đúng bản gần nhất và đối chiếu với thời điểm deploy.

Front: Rollback tầng 1 là gì? Back: Tắt feature flag, mất vài giây, không cần deploy lại.

Front: Rollback tầng 2 là gì? Back: Deploy lại artifact hoặc image của phiên bản trước đó.

Front: Rủi ro lớn nhất khi restore database là gì? Back: Mất dữ liệu phát sinh sau thời điểm backup.

Front: Artifact bất biến nghĩa là gì? Back: Cùng một tag luôn ứng với đúng một bản build, không build lại.

Front: Vì sao phải tập rollback trên staging? Back: Để biết lệnh đúng và đo thời gian thật trước khi cần dùng trên production.

Front: Câu hỏi bắt buộc trước mỗi lần deploy là gì? Back: Nếu bước này hỏng thì lùi về đâu, bằng lệnh nào, ai bấm.

Front: Dấu hiệu phải rollback ngay? Back: Smoke test đỏ hoặc lỗi ảnh hưởng người dùng.

Front: Vì sao không sửa nóng trên production khi đang sự cố? Back: Vì mất trạng thái đã biết, khó rollback và khó tái hiện lỗi.

Front: Backup nên được lưu ở đâu? Back: Ở nơi khác với máy chủ production, ví dụ object storage.

Front: Rollback plan tối thiểu gồm những gì? Back: Điều kiện rollback, người bấm, lệnh cụ thể, nguồn backup, cách kiểm tra sau đó.

Chốt lại

Bạn vừa có đủ ba mảnh: biết sao lưu gì, biết chọn tầng rollback nào, và biết viết plan đủ cụ thể để người khác làm theo. Từ giờ, mỗi lần chuẩn bị deploy, hãy tự hỏi câu đó trước khi bấm. Bài tiếp theo là checkpoint: bạn sẽ ghép E2E test, feature flag và rollback thành một quy trình phát hành hoàn chỉnh và tự kiểm tra lại.