Bỏ qua để đến nội dung

Deploy các lần sau (khi có code mới)

Y hệt lần đầu, chỉ khác là VPS đã có .env/TLS sẵn nên không cần lặp lại §3–§4. Nếu bản mới vượt qua một phase chưa từng chạy trên production, làm thêm các bước của phase đó ở §8 — đặc biệt Phase O (§8.5) có bước phải làm trước khi deploy.

Backup trước khi deploy: deploy_local.sh và rollback_to_version.sh tự tạo bộ backup DB + ảnh + cấu hình (YYYYMMDD/predeploy/<timestamp>/) trước khi đổi image, và dừng lại nếu backup lỗi (§9.1). Chỉ bỏ qua bằng --skip-backup "<lý do>".

Trên máy dev:

Terminal window
./scripts/build_backend_image.sh 1.2.0 # hoặc bỏ tham số để tự tăng patch
./scripts/build_frontend_image.sh 1.2.0
# sửa tay docker-compose.prod.yml: image: admin_portal_backend:v1.2.0 / admin_portal_frontend:v1.2.0
# Với mỗi chore(release), rà hướng dẫn theo các màn hình frontend đổi trong diff,
# cập nhật ghi chú phiên bản và chụp lại ảnh liên quan trên stack dev.
(cd docs-site && npm run screenshots && npm run build:all)
./scripts/package_deploy.sh --skip-guide-build # dùng dist vừa build/kiểm tra phía trên
./scripts/export_images.sh
rsync -av --delete --exclude='.env' --exclude='images/' --exclude='credentials/' deploy/ <user>@<vps-ip>:/opt/web_admin/
rsync -av images/ <user>@<vps-ip>:/opt/web_admin/images/

Trên VPS:

Terminal window
cd /opt/web_admin
./scripts/load_images.sh
./scripts/deploy_local.sh
./scripts/install_cron.sh # bản mới có thể thêm job định kỳ (§10)
# Nginx render nginx.conf.template khi khởi động; restart sau khi nhận template/site mới.
docker compose -f docker-compose.prod.yml restart nginx
docker compose -f docker-compose.prod.yml exec nginx nginx -t
curl -fsS https://portal.tinysoft.io.vn/health

Sau deploy, trong trình duyệt đã đăng nhập Portal, mở /guide/ và thử tìm kiếm; đăng xuất rồi mở lại route để xác nhận bị chuyển về /login. Khi chưa đăng nhập, Nginx chuyển tới /login?next=...; trang login hiện nhắc “Đăng nhập Portal rồi mở lại /guide/” vì hiện chưa tiếp tục tự động theo tham số next.

  1. Rà các trang T.3/T.5 cho màn hình nghiệp vụ đổi trong diff của frontend/src/app; cập nhật nội dung và dòng “Kiểm tra lần cuối với Portal vX”.
  2. Chụp lại ảnh liên quan từ stack dev bằng npm run screenshots; không chụp production.
  3. Chạy npm run build:all trong docs-site/. Build bao gồm kiểm tra đồng bộ nguồn DEPLOY.md, nội dung đào tạo, ảnh và liên kết.
  4. Đóng gói site đã build cùng deploy bằng package_deploy.sh --skip-guide-build, rồi chuyển deploy/ lên VPS như quy trình trên. Nếu bỏ qua build riêng, gọi package_deploy.sh không có cờ để script tự chạy npm ci và npm run build:all.
  5. Trên VPS restart Nginx sau khi nhận template mới, kiểm tra nginx -t, /health và quyền truy cập /guide/ ở trạng thái đăng nhập/đăng xuất.

Biến môi trường mới. Deploy không bao giờ sửa .env thật trên VPS (rsync loại trừ .env để không ghi đè secret); chỉ .env.production.example được cập nhật. Sau mỗi lần đẩy bản mới, so tên biến để biết .env còn thiếu gì:

Terminal window
comm -23 <(grep -oE '^[A-Z_]+=' .env.production.example | sort -u) \
<(grep -oE '^[A-Z_]+=' .env | sort -u)

Biến in ra là biến có trong bản mới mà .env chưa có. Đọc chú thích của biến đó trong .env.production.example (và bảng §3), thêm vào .env những biến bản này cần, rồi:

  • biến của backend/frontend: tạo lại container để nạp giá trị mới (restart không đọc lại .env):
    Terminal window
    docker compose -f docker-compose.prod.yml up -d backend frontend
  • biến BACKUP_*: các script backup đọc .env mỗi lần chạy, không cần làm gì thêm.

Biến tùy chọn không dùng tới thì không cần thêm. Sao lưu .env trước khi sửa (cp -p .env .env.bak.$(date -u +%Y%m%d_%H%M%S)) và giữ quyền 600.

load_images.sh nạp 2 image mới vào Docker cục bộ; deploy_local.sh kiểm tra image đã khai trong docker-compose.prod.yml có sẵn cục bộ chưa → up -d → chờ tối đa 60 giây cho backend healthy → kiểm tra thêm: database đã ở migration mới nhất (alembic current có (head)) và API game-client v2 trả 401 khi thiếu key (trả 404 nghĩa là đang chạy image cũ hơn Phase K). Không đạt thì script thoát mã 1. Không có bước build nào chạy trên VPS.

Chỉ cần image bản cũ vẫn còn cache trên VPS (chưa bị docker image prune/docker rmi xóa đi từ lần load_images.sh trước):

Terminal window
./scripts/rollback_to_version.sh <backend-version> <frontend-version>
# vd: ./scripts/rollback_to_version.sh 1.0.0 1.0.0

rollback_to_version.sh từ chối rollback backend về image không chứa migration mà database đang ở (vd rollback về bản trước Phase K sau khi 0029–0031 đã chạy): image đó sẽ crash-loop ở alembic upgrade head. Khi đó: fix-forward, hoặc restore bản backup chụp trước lúc nâng cấp (§9) rồi mới rollback. --force bỏ qua kiểm tra (chỉ khi chắc chắn).

Nếu image bản cũ đã bị xóa khỏi VPS, phải build lại đúng version đó trên máy dev (./scripts/build_backend_image.sh <version-cũ>), rồi export_images.sh + rsync images/ + load_images.sh lại cho version đó trước khi rollback được.

Migration không lùi được: không có cơ chế tự động downgrade database. Riêng 0043_catalog_references_items, 0044_server_inventory_state và 0045_runs_progress_fragments (Phase O) cố ý từ chối downgrade vì sẽ làm mất dữ liệu Catalog đã chuyển đổi và sổ cái kinh tế/kho đồ. Lùi qua chúng chỉ có một cách: restore backup DB chụp trước khi deploy Phase O (cùng backup ảnh cùng ngày). Các phase sau cũng có migration không nên lùi:

  • 0050_profile_cosmetics (Phase P): downgrade xóa luôn bảng sở hữu và lịch sử cosmetic, nên không downgrade sau khi đã cấp thưởng.
  • 0051_phase_q_gift_campaigns (Phase Q): từ chối downgrade khi đã có snapshot thưởng hồ sơ hoặc cosmetic cấp từ chiến dịch/quà tặng.
  • 0052_shop_owns_items (Phase R): từ chối downgrade khi còn sản phẩm Shop “Không bán” chưa có giá hoặc vật phẩm pending. Chính migration này tạo sản phẩm “Không bán” cho mọi vật phẩm cũ, nên sau khi deploy Phase R gần như luôn bị chặn.

Lùi qua những migration này cũng chỉ có cách restore backup chụp trước lúc deploy phase đó. Còn lại, ưu tiên fix-forward (vá lỗi, deploy lại) thay vì downgrade thủ công.


Áp dụng cho Portal v1.2.2