docs: dịch 22 file Markdown còn lại sang tiếng Việt có dấu (TEC-2881)
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 18s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m15s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 17s
E2E Tests / Playwright E2E (push) Failing after 31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m46s
Security Scanning / Trivy Scan — Web Image (push) Failing after 1m7s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 53s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 18s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m15s
Deploy / Build API Image (push) Failing after 28s
Deploy / Build Web Image (push) Failing after 16s
Deploy / Build AI Services Image (push) Failing after 17s
E2E Tests / Playwright E2E (push) Failing after 31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 3s
Security Scanning / Trivy Scan — API Image (push) Failing after 1m46s
Security Scanning / Trivy Scan — Web Image (push) Failing after 1m7s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 53s
Security Scanning / Trivy Filesystem Scan (push) Failing after 35s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Security Scanning / Security Gate (push) Failing after 0s
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
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>
This commit is contained in:
@@ -1,96 +1,96 @@
|
||||
# Deployment Guide
|
||||
# Hướng Dẫn Deployment
|
||||
|
||||
## Overview
|
||||
## Tổng Quan
|
||||
|
||||
GoodGo Platform AI consists of four deployable services:
|
||||
GoodGo Platform AI gồm bốn dịch vụ có thể deploy:
|
||||
|
||||
| Service | Technology | Default Port |
|
||||
| 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 | Various |
|
||||
| **Infrastructure** | Docker Compose | Khác nhau |
|
||||
|
||||
## Prerequisites
|
||||
## Yêu Cầu Trước
|
||||
|
||||
- Docker Engine 24+ & Docker Compose v2
|
||||
- Node.js 22 LTS
|
||||
- pnpm 10.27+
|
||||
- Python 3.12 (for AI services, if running outside Docker)
|
||||
- Python 3.12 (cho AI services, nếu chạy ngoài Docker)
|
||||
|
||||
## Environment Configuration
|
||||
## Cấu Hình Môi Trường
|
||||
|
||||
Copy `.env.example` to `.env` and configure all required values:
|
||||
Sao chép `.env.example` thành `.env` và cấu hình tất cả giá trị bắt buộc:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Required Variables
|
||||
### Biến Bắt Buộc
|
||||
|
||||
| Variable | Description | Example |
|
||||
| Biến | Mô tả | Ví dụ |
|
||||
|----------|-------------|---------|
|
||||
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@host:5432/goodgo` |
|
||||
| `JWT_SECRET` | JWT signing key (min 32 chars) | Generate with `openssl rand -hex 32` |
|
||||
| `JWT_REFRESH_SECRET` | Refresh token signing key | Generate with `openssl rand -hex 32` |
|
||||
| `REDIS_URL` | Redis connection string | `redis://localhost:6379` |
|
||||
| `TYPESENSE_API_KEY` | Typesense admin API key | Generate a secure random key |
|
||||
| `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 |
|
||||
|
||||
### Optional Variables
|
||||
### Biến Tùy Chọn
|
||||
|
||||
| Variable | Description | Default |
|
||||
| Biến | Mô tả | Mặc định |
|
||||
|----------|-------------|---------|
|
||||
| `API_PORT` | API server port | `3000` |
|
||||
| `WEB_PORT` | Web app port | `3001` |
|
||||
| `NODE_ENV` | Environment mode | `development` |
|
||||
| `CORS_ORIGINS` | Allowed CORS origins | — |
|
||||
| `CLAUDE_API_KEY` | Claude API key (for content moderation) | — |
|
||||
| `NEXT_PUBLIC_MAPBOX_TOKEN` | Mapbox token (for maps) | — |
|
||||
| `VNPAY_*`, `MOMO_*`, `ZALOPAY_*` | Payment gateway credentials | — |
|
||||
| `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 | — |
|
||||
|
||||
## Infrastructure Setup (Docker Compose)
|
||||
## Cài Đặt Hạ Tầng (Docker Compose)
|
||||
|
||||
Start all infrastructure services:
|
||||
Khởi động tất cả dịch vụ hạ tầng:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This starts:
|
||||
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** — automated daily PostgreSQL backups at 02:00 UTC with verification at 04:00 UTC
|
||||
- **Loki** (port 3100) — log aggregation
|
||||
- **Promtail** — log collection agent (ships container logs to Loki)
|
||||
- **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) — dashboards for metrics and logs
|
||||
- **Grafana** (port 3002) — dashboard cho metric và log
|
||||
|
||||
Verify all services are healthy:
|
||||
Kiểm tra tất cả dịch vụ đang khỏe mạnh:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
All services include health checks. Wait until all show `healthy` status.
|
||||
Tất cả dịch vụ đều có health check. Đợi đến khi tất cả hiển thị trạng thái `healthy`.
|
||||
|
||||
## Database Setup
|
||||
## Cài Đặt Database
|
||||
|
||||
```bash
|
||||
# Generate Prisma client
|
||||
# Sinh Prisma client
|
||||
pnpm db:generate
|
||||
|
||||
# Apply migrations
|
||||
# Áp dụng migration
|
||||
pnpm db:migrate:deploy
|
||||
|
||||
# Seed initial data (optional)
|
||||
# Seed dữ liệu khởi tạo (tùy chọn)
|
||||
pnpm db:seed
|
||||
```
|
||||
|
||||
## Building for Production
|
||||
## Build cho Production
|
||||
|
||||
### API (NestJS)
|
||||
|
||||
@@ -101,7 +101,7 @@ pnpm build
|
||||
|
||||
Output: `apps/api/dist/`
|
||||
|
||||
Run in production:
|
||||
Chạy trong production:
|
||||
|
||||
```bash
|
||||
NODE_ENV=production PORT=3001 node apps/api/dist/main.js
|
||||
@@ -116,7 +116,7 @@ pnpm build
|
||||
|
||||
Output: `apps/web/.next/`
|
||||
|
||||
Run in production:
|
||||
Chạy trong production:
|
||||
|
||||
```bash
|
||||
NODE_ENV=production pnpm --filter web start
|
||||
@@ -124,7 +124,7 @@ NODE_ENV=production pnpm --filter web start
|
||||
|
||||
### AI Services (FastAPI)
|
||||
|
||||
The AI service runs in Docker via `docker compose`. To build separately:
|
||||
AI service chạy trong Docker qua `docker compose`. Để build riêng:
|
||||
|
||||
```bash
|
||||
cd libs/ai-services
|
||||
@@ -132,64 +132,64 @@ docker build -t goodgo-ai-services .
|
||||
docker run -p 8000:8000 --env-file ../../.env goodgo-ai-services
|
||||
```
|
||||
|
||||
## Production Checklist
|
||||
## Checklist Production
|
||||
|
||||
### Security
|
||||
### Bảo Mật
|
||||
|
||||
- [ ] Set strong, unique `JWT_SECRET` and `JWT_REFRESH_SECRET` (min 32 characters)
|
||||
- [ ] Set `NODE_ENV=production`
|
||||
- [ ] Configure `CORS_ORIGINS` to only allow your domain(s)
|
||||
- [ ] Change default database passwords
|
||||
- [ ] Change default MinIO credentials (`MINIO_USER`, `MINIO_PASSWORD`)
|
||||
- [ ] Change default Grafana credentials (`GRAFANA_ADMIN_USER`, `GRAFANA_ADMIN_PASSWORD`)
|
||||
- [ ] Use a strong, unique `TYPESENSE_API_KEY`
|
||||
- [ ] Enable SSL/TLS termination (reverse proxy)
|
||||
- [ ] Set `MINIO_USE_SSL=true` if MinIO is exposed publicly
|
||||
- [ ] Đặt `JWT_SECRET` và `JWT_REFRESH_SECRET` mạnh, độc nhất (tối thiểu 32 ký tự)
|
||||
- [ ] Đặt `NODE_ENV=production`
|
||||
- [ ] Cấu hình `CORS_ORIGINS` chỉ 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_KEY` mạnh, độc nhất
|
||||
- [ ] Bật SSL/TLS termination (reverse proxy)
|
||||
- [ ] Đặt `MINIO_USE_SSL=true` nếu MinIO được public
|
||||
|
||||
### Database
|
||||
|
||||
- [ ] Run `pnpm db:migrate:deploy` (not `db:migrate:dev`)
|
||||
- [ ] Enable PostgreSQL connection pooling (PgBouncer recommended)
|
||||
- [ ] Configure automated backups
|
||||
- [ ] Set appropriate `max_connections` in PostgreSQL config
|
||||
- [ ] Chạy `pnpm db:migrate:deploy` (không dùng `db:migrate:dev`)
|
||||
- [ ] Bật connection pooling cho PostgreSQL (khuyến nghị PgBouncer)
|
||||
- [ ] Cấu hình backup tự động
|
||||
- [ ] Đặt `max_connections` phù hợp trong cấu hình PostgreSQL
|
||||
|
||||
### Monitoring
|
||||
|
||||
- [ ] Verify Prometheus is scraping `/metrics` endpoint
|
||||
- [ ] Import Grafana dashboards from `monitoring/grafana/dashboards/`
|
||||
- [ ] Set up alerting rules for error rates and latency
|
||||
- [ ] 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
|
||||
|
||||
- [ ] Configure Redis `maxmemory` and eviction policy
|
||||
- [ ] Set appropriate Typesense `--memory-limit`
|
||||
- [ ] Enable gzip/brotli compression in reverse proxy
|
||||
- [ ] Configure CDN for static assets (Next.js `/_next/static/`)
|
||||
- [ ] Cấu hình Redis `maxmemory` và chính sách eviction
|
||||
- [ ] Đặt `--memory-limit` phù 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 Checks
|
||||
## Health Check
|
||||
|
||||
| Service | Endpoint | Expected Response |
|
||||
| Dịch vụ | Endpoint | Phản hồi mong đợi |
|
||||
|---------|----------|-------------------|
|
||||
| API | `GET /health` | `{"status": "ok"}` |
|
||||
| API (Swagger) | `GET /api/v1/docs` | Swagger UI page |
|
||||
| API (Metrics) | `GET /api/v1/metrics` | Prometheus metrics |
|
||||
| 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 |
|
||||
|
||||
## Scaling Considerations
|
||||
## Cân Nhắc Về Scaling
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
- **API**: Stateless — scale with multiple instances behind a load balancer
|
||||
- **Web**: Stateless — scale with multiple instances or deploy to Vercel/Cloudflare
|
||||
- **AI Services**: CPU-bound — scale based on valuation request volume
|
||||
- **Redis**: Use Redis Cluster for high availability
|
||||
- **PostgreSQL**: Read replicas for query-heavy workloads
|
||||
- **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
|
||||
|
||||
### Recommended Architecture (Production)
|
||||
### Kiến Trúc Khuyến Nghị (Production)
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
@@ -216,143 +216,143 @@ docker run -p 8000:8000 --env-file ../../.env goodgo-ai-services
|
||||
|
||||
## CI/CD Pipeline
|
||||
|
||||
### Branch Strategy
|
||||
### Chiến Lược Branch
|
||||
|
||||
| Branch | Deploy Target | Trigger | Notes |
|
||||
| Branch | Đích deploy | Trigger | Ghi chú |
|
||||
|--------|--------------|---------|-------|
|
||||
| `develop` | Staging | Auto (push) | Every merge to `develop` auto-deploys to staging |
|
||||
| `master` | Staging | Auto (push) | Master push also deploys to staging for verification |
|
||||
| Manual | Staging/Production | `workflow_dispatch` | Manual trigger via GitHub Actions UI |
|
||||
| `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 |
|
||||
|
||||
### Staging Auto-Deploy Flow
|
||||
### Quy Trình Auto-Deploy Staging
|
||||
|
||||
```
|
||||
Push to develop → Build images → Tag rollback → Deploy to staging → Smoke tests → Cleanup / Rollback
|
||||
```
|
||||
|
||||
1. **Build**: Docker images for API, Web, and AI Services are built and pushed to GHCR with `staging-latest` tag
|
||||
2. **Tag rollback**: Current running images are tagged as `:rollback` before new images are pulled
|
||||
3. **Deploy**: New images are pulled and services are updated via rolling restart (zero-downtime)
|
||||
4. **Verify**: Health check polls `$STAGING_URL/health` for up to 100 seconds
|
||||
5. **Smoke test**: `scripts/smoke-test.sh` runs against the staging URL, checking health probes, core API endpoints, search, and auth
|
||||
6. **Cleanup**: On success, `:rollback` tags are removed and `docker image prune` cleans up old layers
|
||||
7. **Notify**: Slack notification on success or failure
|
||||
8. **Rollback**: If smoke tests fail, automatic rollback restores the `:rollback` tagged images
|
||||
1. **Build**: Docker image cho API, Web, và AI Services được build và push lên GHCR với tag `staging-latest`
|
||||
2. **Tag rollback**: Image hiện đang chạy được tag là `:rollback` trước khi pull image mới
|
||||
3. **Deploy**: Image mới được pull và dịch vụ được cập nhật qua rolling restart (zero-downtime)
|
||||
4. **Verify**: Health check poll `$STAGING_URL/health` trong tối đa 100 giây
|
||||
5. **Smoke test**: `scripts/smoke-test.sh` chạy với staging URL, kiểm tra health probe, các endpoint API cốt lõi, search và auth
|
||||
6. **Cleanup**: Khi thành công, các tag `:rollback` được xóa và `docker image prune` dọn dẹp các layer cũ
|
||||
7. **Notify**: Thông báo Slack khi thành công hoặc thất bại
|
||||
8. **Rollback**: Nếu smoke test thất bại, rollback tự động khôi phục image có tag `:rollback`
|
||||
|
||||
### Notifications
|
||||
### Thông Báo
|
||||
|
||||
Deploy status notifications are sent to Slack via `SLACK_WEBHOOK_URL` secret:
|
||||
Trạng thái deploy được gửi đến Slack qua secret `SLACK_WEBHOOK_URL`:
|
||||
|
||||
| Event | Channel | Content |
|
||||
| Sự kiện | Kênh | Nội dung |
|
||||
|-------|---------|---------|
|
||||
| Staging smoke tests pass | Slack | ✅ Commit SHA, branch, link to run |
|
||||
| Staging smoke tests fail | Slack | 🚨 Commit SHA, branch, link to run |
|
||||
| Staging rollback triggered | Slack | ⚠️ Commit SHA, reason, link to run |
|
||||
| Production deploy success | Slack | ✅ Commit SHA, branch |
|
||||
| Production rollback triggered | Slack | ⚠️ Commit SHA, reason, link to run |
|
||||
| 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 |
|
||||
|
||||
### Required Secrets
|
||||
### Secret Bắt Buộc
|
||||
|
||||
| Secret | Environment | Description |
|
||||
| Secret | Môi trường | Mô tả |
|
||||
|--------|-------------|-------------|
|
||||
| `STAGING_HOST` | staging | Staging server hostname/IP |
|
||||
| `STAGING_USER` | staging | SSH user for staging deploys |
|
||||
| `STAGING_SSH_KEY` | staging | SSH private key for staging |
|
||||
| `STAGING_URL` | staging | Staging base URL (e.g., `https://staging.goodgo.vn`) |
|
||||
| `PRODUCTION_HOST` | production | Production server hostname/IP |
|
||||
| `PRODUCTION_USER` | production | SSH user for production deploys |
|
||||
| `PRODUCTION_SSH_KEY` | production | SSH private key for production |
|
||||
| `PRODUCTION_URL` | production | Production base URL |
|
||||
| `SLACK_WEBHOOK_URL` | both | Slack incoming webhook URL |
|
||||
| `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
|
||||
|
||||
### Rollback Safety Mechanism
|
||||
### Cơ Chế An Toàn Khi Rollback
|
||||
|
||||
The deploy pipeline uses **explicit `:rollback` image tags** to guarantee safe rollbacks. Here's how it works:
|
||||
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:
|
||||
|
||||
1. **Before pulling new images**: The current running images are tagged as `goodgo-api:rollback`, `goodgo-web:rollback`, and `goodgo-ai-services:rollback`
|
||||
2. **After pulling new images**: Services are updated with the new images via rolling restart
|
||||
3. **After smoke tests pass**: The `:rollback` tags are removed and `docker image prune` cleans up old layers
|
||||
4. **If smoke tests fail**: The `:rollback` tagged images are used to restore the previous version
|
||||
1. **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`
|
||||
2. **Sau khi pull image mới**: Dịch vụ được cập nhật với image mới qua rolling restart
|
||||
3. **Sau khi smoke test pass**: Tag `:rollback` được xóa và `docker image prune` dọn dẹp layer cũ
|
||||
4. **Nếu smoke test fail**: Image có tag `:rollback` được dùng để khôi phục phiên bản trước
|
||||
|
||||
This ensures that `docker image prune` never deletes the images needed for rollback, because:
|
||||
- Image pruning only happens **after** smoke tests pass
|
||||
- The `:rollback` tags keep the previous images pinned even if pruning were to run accidentally
|
||||
Đ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 `:rollback` giữ image trước được pin lại ngay cả khi pruning vô tình chạy
|
||||
|
||||
### Automatic Rollback (Staging)
|
||||
### Rollback Tự Động (Staging)
|
||||
|
||||
The staging pipeline includes automatic rollback when smoke tests fail:
|
||||
Pipeline staging có rollback tự động khi smoke test thất bại:
|
||||
|
||||
1. **Pre-deploy**: Current container images are tagged with `:rollback` suffix before new images are pulled
|
||||
2. **Smoke test failure**: If `scripts/smoke-test.sh` exits non-zero, the `rollback-staging` job triggers
|
||||
3. **Rollback execution**: Containers are stopped and restarted using the `:rollback` tagged images
|
||||
4. **Verification**: Health check confirms the rollback succeeded
|
||||
5. **Notification**: Slack notification reports the rollback with links to the failed run
|
||||
1. **Trước deploy**: Image container hiện tại được tag với hậu tố `:rollback` trước khi pull image mới
|
||||
2. **Smoke test thất bại**: Nếu `scripts/smoke-test.sh` thoát non-zero, job `rollback-staging` được trigger
|
||||
3. **Thực hiện rollback**: Container được dừng và khởi động lại bằng image có tag `:rollback`
|
||||
4. **Verify**: Health check xác nhận rollback đã thành công
|
||||
5. **Notification**: Slack báo cáo rollback kèm link đến run thất bại
|
||||
|
||||
### Automatic Rollback (Production)
|
||||
### Rollback Tự Động (Production)
|
||||
|
||||
Same mechanism as staging — smoke test failure triggers `rollback-production` using the `:rollback` tagged images.
|
||||
Cơ chế giống staging — smoke test thất bại sẽ trigger `rollback-production` dùng image có tag `:rollback`.
|
||||
|
||||
### Manual Rollback
|
||||
### Rollback Thủ Công
|
||||
|
||||
To manually rollback a staging or production deployment:
|
||||
Để rollback thủ công một deployment staging hoặc production:
|
||||
|
||||
#### Option 1: Re-deploy a known-good commit
|
||||
#### Lựa chọn 1: Re-deploy một commit đã biết là tốt
|
||||
|
||||
```bash
|
||||
# Trigger a deploy of a specific commit via GitHub Actions
|
||||
# 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
|
||||
```
|
||||
|
||||
#### Option 2: SSH rollback using :rollback tags (fastest)
|
||||
#### Lựa chọn 2: SSH rollback dùng tag :rollback (nhanh nhất)
|
||||
|
||||
```bash
|
||||
# SSH into the staging/production server
|
||||
# SSH vào server staging/production
|
||||
ssh deploy@<host>
|
||||
cd ~/goodgo
|
||||
|
||||
# Stop current services
|
||||
# Dừng dịch vụ hiện tại
|
||||
docker compose -f docker-compose.prod.yml stop api web ai-services
|
||||
|
||||
# Verify :rollback images exist
|
||||
# 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"
|
||||
|
||||
# Restart services (compose picks up cached/rollback images)
|
||||
# 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"
|
||||
```
|
||||
|
||||
> **Note:** The `:rollback` tags are only available until the next successful deploy cleans them up. If you need to roll back to an older version, use Option 3 below.
|
||||
> **Lưu ý:** Tag `:rollback` chỉ 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.
|
||||
|
||||
#### Option 3: Pin to a specific image tag
|
||||
#### Lựa chọn 3: Pin về một image tag cụ thể
|
||||
|
||||
```bash
|
||||
ssh deploy@<host>
|
||||
cd ~/goodgo
|
||||
|
||||
# Set IMAGE_TAG to a known-good SHA
|
||||
# Đặ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 and restart with the pinned tag
|
||||
# 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
|
||||
```
|
||||
|
||||
#### Option 4: Use deploy-production.sh (built-in rollback)
|
||||
#### Lựa chọn 4: Dùng deploy-production.sh (rollback tích hợp sẵn)
|
||||
|
||||
The manual deploy script (`scripts/deploy-production.sh`) has integrated rollback support:
|
||||
- Automatically tags `:rollback` images before pulling
|
||||
- Runs health checks and smoke tests
|
||||
- Auto-rollbacks using `:rollback` tags if either fails
|
||||
- Only prunes images after smoke tests pass
|
||||
Script deploy thủ công (`scripts/deploy-production.sh`) có hỗ trợ rollback tích hợp:
|
||||
- Tự động tag image `:rollback` trước khi pull
|
||||
- Chạy health check và smoke test
|
||||
- Tự rollback dùng tag `:rollback` nếu một trong hai thất bại
|
||||
- Chỉ prune image sau khi smoke test pass
|
||||
|
||||
```bash
|
||||
ssh ubuntu@185.225.232.65
|
||||
@@ -360,21 +360,21 @@ cd ~/goodgo
|
||||
./scripts/deploy-production.sh [image-tag]
|
||||
```
|
||||
|
||||
### Database Rollback
|
||||
### Rollback Database
|
||||
|
||||
Prisma does not support automatic down migrations. If a migration must be reverted:
|
||||
Prisma không hỗ trợ down migration tự động. Nếu một migration cần được hoàn tác:
|
||||
|
||||
1. Identify the migration in `prisma/migrations/`
|
||||
2. Write a manual SQL rollback script
|
||||
3. Apply via `psql` or a migration tool
|
||||
4. Update `_prisma_migrations` table
|
||||
1. Xác định migration trong `prisma/migrations/`
|
||||
2. Viết script rollback SQL thủ công
|
||||
3. Áp dụng qua `psql` hoặc công cụ migration
|
||||
4. Cập nhật bảng `_prisma_migrations`
|
||||
|
||||
Always test migrations against a staging database before production deployment.
|
||||
Luôn test migration với database staging trước khi deploy production.
|
||||
|
||||
### Post-Rollback Checklist
|
||||
### Checklist Sau Rollback
|
||||
|
||||
- [ ] Verify health endpoints respond: `GET /health`, `GET /ready`
|
||||
- [ ] Run smoke tests manually: `./scripts/smoke-test.sh <url>`
|
||||
- [ ] Check application logs: `docker compose -f docker-compose.prod.yml logs --tail=100 api web`
|
||||
- [ ] Confirm Grafana dashboards show normal metrics
|
||||
- [ ] Notify the team via Slack about the rollback and root cause
|
||||
- [ ] 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
|
||||
|
||||
Reference in New Issue
Block a user