Hoàn tất đợt cuối của nhiệm vụ chuyển toàn bộ tài liệu sang tiếng Việt. Đã dịch 22 file `.md` còn sót (~9.7k dòng) — gồm RUNBOOK, audits, docs/architecture, docs/load-testing, libs READMEs và các quick references. Giữ nguyên code blocks, đường dẫn, identifier kỹ thuật, URL và biến môi trường. Co-Authored-By: Paperclip <noreply@paperclip.ing>
14 KiB
Hướng Dẫn Deployment
Tổng Quan
GoodGo Platform AI gồm bốn dịch vụ có thể deploy:
| Dịch vụ | Công nghệ | Port mặc định |
|---|---|---|
| API | NestJS (Node.js) | 3001 |
| Web | Next.js | 3000 |
| AI Services | FastAPI (Python) | 8000 |
| Infrastructure | Docker Compose | Khác nhau |
Yêu Cầu Trước
- Docker Engine 24+ & Docker Compose v2
- Node.js 22 LTS
- pnpm 10.27+
- Python 3.12 (cho AI services, nếu chạy ngoài Docker)
Cấu Hình Môi Trường
Sao chép .env.example thành .env và cấu hình tất cả giá trị bắt buộc:
cp .env.example .env
Biến Bắt Buộc
| Biến | Mô tả | Ví dụ |
|---|---|---|
DATABASE_URL |
Chuỗi kết nối PostgreSQL | postgresql://user:pass@host:5432/goodgo |
JWT_SECRET |
Khóa ký JWT (tối thiểu 32 ký tự) | Tạo bằng openssl rand -hex 32 |
JWT_REFRESH_SECRET |
Khóa ký refresh token | Tạo bằng openssl rand -hex 32 |
REDIS_URL |
Chuỗi kết nối Redis | redis://localhost:6379 |
TYPESENSE_API_KEY |
API key admin Typesense | Tạo một khóa ngẫu nhiên an toàn |
Biến Tùy Chọn
| Biến | Mô tả | Mặc định |
|---|---|---|
API_PORT |
Port API server | 3000 |
WEB_PORT |
Port web app | 3001 |
NODE_ENV |
Chế độ môi trường | development |
CORS_ORIGINS |
Các origin CORS được phép | — |
CLAUDE_API_KEY |
Claude API key (cho content moderation) | — |
NEXT_PUBLIC_MAPBOX_TOKEN |
Token Mapbox (cho bản đồ) | — |
VNPAY_*, MOMO_*, ZALOPAY_* |
Thông tin payment gateway | — |
Cài Đặt Hạ Tầng (Docker Compose)
Khởi động tất cả dịch vụ hạ tầng:
docker compose up -d
Lệnh này khởi động:
- PostgreSQL 16 + PostGIS 3.4 (port 5432)
- Redis 7 (port 6379)
- Typesense 27 (port 8108)
- MinIO (API: 9000, Console: 9001)
- AI Services (port 8000)
- pg-backup — backup PostgreSQL hằng ngày tự động lúc 02:00 UTC, có verify lúc 04:00 UTC
- Loki (port 3100) — tổng hợp log
- Promtail — agent thu thập log (chuyển log container đến Loki)
- Prometheus (port 9090)
- Grafana (port 3002) — dashboard cho metric và log
Kiểm tra tất cả dịch vụ đang khỏe mạnh:
docker compose ps
Tất cả dịch vụ đều có health check. Đợi đến khi tất cả hiển thị trạng thái healthy.
Cài Đặt Database
# Sinh Prisma client
pnpm db:generate
# Áp dụng migration
pnpm db:migrate:deploy
# Seed dữ liệu khởi tạo (tùy chọn)
pnpm db:seed
Build cho Production
API (NestJS)
cd apps/api
pnpm build
Output: apps/api/dist/
Chạy trong production:
NODE_ENV=production PORT=3001 node apps/api/dist/main.js
Web (Next.js)
cd apps/web
pnpm build
Output: apps/web/.next/
Chạy trong production:
NODE_ENV=production pnpm --filter web start
AI Services (FastAPI)
AI service chạy trong Docker qua docker compose. Để build riêng:
cd libs/ai-services
docker build -t goodgo-ai-services .
docker run -p 8000:8000 --env-file ../../.env goodgo-ai-services
Checklist Production
Bảo Mật
- Đặt
JWT_SECRETvàJWT_REFRESH_SECRETmạnh, độc nhất (tối thiểu 32 ký tự) - Đặt
NODE_ENV=production - Cấu hình
CORS_ORIGINSchỉ cho phép domain của bạn - Đổi mật khẩu database mặc định
- Đổi credential MinIO mặc định (
MINIO_USER,MINIO_PASSWORD) - Đổi credential Grafana mặc định (
GRAFANA_ADMIN_USER,GRAFANA_ADMIN_PASSWORD) - Dùng
TYPESENSE_API_KEYmạnh, độc nhất - Bật SSL/TLS termination (reverse proxy)
- Đặt
MINIO_USE_SSL=truenếu MinIO được public
Database
- Chạy
pnpm db:migrate:deploy(không dùngdb:migrate:dev) - Bật connection pooling cho PostgreSQL (khuyến nghị PgBouncer)
- Cấu hình backup tự động
- Đặt
max_connectionsphù hợp trong cấu hình PostgreSQL
Monitoring
- Xác nhận Prometheus đang scrape endpoint
/metrics - Import dashboard Grafana từ
monitoring/grafana/dashboards/ - Cài đặt rule alerting cho error rate và latency
Performance
- Cấu hình Redis
maxmemoryvà chính sách eviction - Đặt
--memory-limitphù hợp cho Typesense - Bật nén gzip/brotli ở reverse proxy
- Cấu hình CDN cho static asset (Next.js
/_next/static/)
Health Check
| Dịch vụ | Endpoint | Phản hồi mong đợi |
|---|---|---|
| API | GET /health |
{"status": "ok"} |
| API (Swagger) | GET /api/v1/docs |
Trang Swagger UI |
| API (Metrics) | GET /api/v1/metrics |
Metric Prometheus |
| AI Services | GET /health |
{"status": "ok"} |
| Typesense | GET /health |
{"ok": true} |
| Loki | GET /ready |
200 OK |
| Redis | redis-cli ping |
PONG |
| PostgreSQL | pg_isready -h host -p 5432 |
Exit code 0 |
Cân Nhắc Về Scaling
Horizontal Scaling
- API: Stateless — scale với nhiều instance phía sau load balancer
- Web: Stateless — scale với nhiều instance hoặc deploy lên Vercel/Cloudflare
- AI Services: CPU-bound — scale theo lượng yêu cầu định giá
- Redis: Dùng Redis Cluster cho tính sẵn sàng cao
- PostgreSQL: Read replica cho workload nhiều truy vấn
Kiến Trúc Khuyến Nghị (Production)
┌─────────────┐
│ Load Balancer│
│ (nginx/ALB) │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
┌─────▼──┐ ┌─────▼──┐ ┌─────▼──┐
│ API #1 │ │ API #2 │ │ API #N │
└────────┘ └────────┘ └────────┘
│ │ │
└────────────┼────────────┘
│
┌────────────┼────────────┐
│ │ │
┌─────▼──┐ ┌─────▼──┐ ┌─────▼─────┐
│ PG │ │ Redis │ │ Typesense │
│Primary │ │Cluster │ │ Cluster │
│+ Replica│ │ │ │ │
└────────┘ └────────┘ └────────────┘
CI/CD Pipeline
Chiến Lược Branch
| Branch | Đích deploy | Trigger | Ghi chú |
|---|---|---|---|
develop |
Staging | Tự động (push) | Mọi merge vào develop đều tự deploy lên staging |
master |
Staging | Tự động (push) | Push master cũng deploy lên staging để verify |
| Manual | Staging/Production | workflow_dispatch |
Trigger thủ công qua GitHub Actions UI |
Quy Trình Auto-Deploy Staging
Push to develop → Build images → Tag rollback → Deploy to staging → Smoke tests → Cleanup / Rollback
- Build: Docker image cho API, Web, và AI Services được build và push lên GHCR với tag
staging-latest - Tag rollback: Image hiện đang chạy được tag là
:rollbacktrước khi pull image mới - Deploy: Image mới được pull và dịch vụ được cập nhật qua rolling restart (zero-downtime)
- Verify: Health check poll
$STAGING_URL/healthtrong tối đa 100 giây - Smoke test:
scripts/smoke-test.shchạy với staging URL, kiểm tra health probe, các endpoint API cốt lõi, search và auth - Cleanup: Khi thành công, các tag
:rollbackđược xóa vàdocker image prunedọn dẹp các layer cũ - Notify: Thông báo Slack khi thành công hoặc thất bại
- Rollback: Nếu smoke test thất bại, rollback tự động khôi phục image có tag
:rollback
Thông Báo
Trạng thái deploy được gửi đến Slack qua secret SLACK_WEBHOOK_URL:
| Sự kiện | Kênh | Nội dung |
|---|---|---|
| Smoke test staging pass | Slack | ✅ Commit SHA, branch, link đến run |
| Smoke test staging fail | Slack | 🚨 Commit SHA, branch, link đến run |
| Trigger rollback staging | Slack | ⚠️ Commit SHA, lý do, link đến run |
| Deploy production thành công | Slack | ✅ Commit SHA, branch |
| Trigger rollback production | Slack | ⚠️ Commit SHA, lý do, link đến run |
Secret Bắt Buộc
| Secret | Môi trường | Mô tả |
|---|---|---|
STAGING_HOST |
staging | Hostname/IP server staging |
STAGING_USER |
staging | User SSH cho deploy staging |
STAGING_SSH_KEY |
staging | Khóa SSH private cho staging |
STAGING_URL |
staging | URL gốc staging (vd: https://staging.goodgo.vn) |
PRODUCTION_HOST |
production | Hostname/IP server production |
PRODUCTION_USER |
production | User SSH cho deploy production |
PRODUCTION_SSH_KEY |
production | Khóa SSH private cho production |
PRODUCTION_URL |
production | URL gốc production |
SLACK_WEBHOOK_URL |
cả hai | URL incoming webhook Slack |
Rollback
Cơ Chế An Toàn Khi Rollback
Pipeline deploy sử dụng tag image :rollback rõ ràng để bảo đảm rollback an toàn. Cách hoạt động như sau:
- Trước khi pull image mới: Image hiện đang chạy được tag là
goodgo-api:rollback,goodgo-web:rollback, vàgoodgo-ai-services:rollback - Sau khi pull image mới: Dịch vụ được cập nhật với image mới qua rolling restart
- Sau khi smoke test pass: Tag
:rollbackđược xóa vàdocker image prunedọn dẹp layer cũ - Nếu smoke test fail: Image có tag
:rollbackđược dùng để khôi phục phiên bản trước
Điều này bảo đảm docker image prune không bao giờ xóa image cần cho rollback, vì:
- Image pruning chỉ xảy ra sau khi smoke test pass
- Tag
:rollbackgiữ image trước được pin lại ngay cả khi pruning vô tình chạy
Rollback Tự Động (Staging)
Pipeline staging có rollback tự động khi smoke test thất bại:
- Trước deploy: Image container hiện tại được tag với hậu tố
:rollbacktrước khi pull image mới - Smoke test thất bại: Nếu
scripts/smoke-test.shthoát non-zero, jobrollback-stagingđược trigger - Thực hiện rollback: Container được dừng và khởi động lại bằng image có tag
:rollback - Verify: Health check xác nhận rollback đã thành công
- Notification: Slack báo cáo rollback kèm link đến run thất bại
Rollback Tự Động (Production)
Cơ chế giống staging — smoke test thất bại sẽ trigger rollback-production dùng image có tag :rollback.
Rollback Thủ Công
Để rollback thủ công một deployment staging hoặc production:
Lựa chọn 1: Re-deploy một commit đã biết là tốt
# Trigger deploy của một commit cụ thể qua GitHub Actions
gh workflow run deploy.yml \
--ref <known-good-commit-or-branch> \
-f environment=staging
Lựa chọn 2: SSH rollback dùng tag :rollback (nhanh nhất)
# SSH vào server staging/production
ssh deploy@<host>
cd ~/goodgo
# Dừng dịch vụ hiện tại
docker compose -f docker-compose.prod.yml stop api web ai-services
# Xác nhận image :rollback tồn tại
docker image inspect goodgo-api:rollback > /dev/null 2>&1 && echo "API rollback available"
docker image inspect goodgo-web:rollback > /dev/null 2>&1 && echo "Web rollback available"
docker image inspect goodgo-ai-services:rollback > /dev/null 2>&1 && echo "AI rollback available"
# Khởi động lại dịch vụ (compose lấy image cache/rollback)
docker compose -f docker-compose.prod.yml up -d --wait api web ai-services
# Verify health
curl -sf http://localhost:3001/health && echo "Rollback successful"
Lưu ý: Tag
:rollbackchỉ có sẵn cho đến khi lần deploy thành công kế tiếp dọn chúng đi. Nếu cần rollback về phiên bản cũ hơn, dùng Lựa chọn 3 dưới đây.
Lựa chọn 3: Pin về một image tag cụ thể
ssh deploy@<host>
cd ~/goodgo
# Đặt IMAGE_TAG về một SHA đã biết là tốt
export IMAGE_TAG=<known-good-commit-sha>
export REGISTRY_URL=ghcr.io/<owner>
# Pull và khởi động lại với tag đã pin
docker compose -f docker-compose.prod.yml pull api web ai-services
docker compose -f docker-compose.prod.yml up -d --no-deps --wait api web ai-services
Lựa chọn 4: Dùng deploy-production.sh (rollback tích hợp sẵn)
Script deploy thủ công (scripts/deploy-production.sh) có hỗ trợ rollback tích hợp:
- Tự động tag image
:rollbacktrước khi pull - Chạy health check và smoke test
- Tự rollback dùng tag
:rollbacknếu một trong hai thất bại - Chỉ prune image sau khi smoke test pass
ssh ubuntu@185.225.232.65
cd ~/goodgo
./scripts/deploy-production.sh [image-tag]
Rollback Database
Prisma không hỗ trợ down migration tự động. Nếu một migration cần được hoàn tác:
- Xác định migration trong
prisma/migrations/ - Viết script rollback SQL thủ công
- Áp dụng qua
psqlhoặc công cụ migration - Cập nhật bảng
_prisma_migrations
Luôn test migration với database staging trước khi deploy production.
Checklist Sau Rollback
- Xác nhận health endpoint phản hồi:
GET /health,GET /ready - Chạy smoke test thủ công:
./scripts/smoke-test.sh <url> - Kiểm tra log ứng dụng:
docker compose -f docker-compose.prod.yml logs --tail=100 api web - Xác nhận dashboard Grafana hiển thị metric bình thường
- Thông báo cho team qua Slack về rollback và nguyên nhân gốc