diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 2b44b936f..c562bfcc7 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -7,177 +7,110 @@ on: - 'v*' jobs: - build: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build API image - run: | - docker build -t xiaoxia-saas-api:${{ github.sha }} \ - -f infra/docker/api.Dockerfile . - - - name: Build Worker image - run: | - docker build -t xiaoxia-saas-worker:${{ github.sha }} \ - -f infra/docker/worker.Dockerfile . - - - name: Save Docker images - run: | - docker save xiaoxia-saas-api:${{ github.sha }} | gzip > api-image.tar.gz - docker save xiaoxia-saas-worker:${{ github.sha }} | gzip > worker-image.tar.gz - - - name: Move images to temp - run: | - mv api-image.tar.gz /tmp/ - mv worker-image.tar.gz /tmp/ - deploy-staging: + name: Deploy Staging runs-on: ubuntu-latest - needs: build if: github.ref == 'refs/heads/main' - + steps: - name: Checkout code uses: actions/checkout@v3 - - - name: Deploy to staging + + - name: Sync code to staging workspace run: | - # Load Docker images - docker load < /tmp/api-image.tar.gz - docker load < /tmp/worker-image.tar.gz - - # Prepare staging directory - mkdir -p /var/lib/xiaoxia-saas-staging - cp .env.staging /var/lib/xiaoxia-saas-staging/.env - - # Tag as staging - docker tag xiaoxia-saas-api:${{ github.sha }} xiaoxia-saas-api:staging - docker tag xiaoxia-saas-worker:${{ github.sha }} xiaoxia-saas-worker:staging - - # Deploy with staging env - cd /var/lib/xiaoxia-saas-staging - cat > docker-compose.yml << 'COMPOSE' -version: '3.9' -services: - api: - image: xiaoxia-saas-api:staging - restart: unless-stopped - env_file: - - ./.env - ports: - - "8001:8000" - depends_on: - - postgres - - redis + mkdir -p /var/lib/xiaoxia-saas-staging/repo + rsync -a --delete --exclude '.git' ./ /var/lib/xiaoxia-saas-staging/repo/ - worker: - image: xiaoxia-saas-worker:staging - restart: unless-stopped - env_file: - - ./.env - depends_on: - - redis - - postgres + - name: Verify staging env file + run: | + test -f /var/lib/xiaoxia-saas-staging/.env - postgres: - image: postgres:16 - restart: unless-stopped - environment: - POSTGRES_DB: xiaoxia_saas_staging - POSTGRES_USER: postgres - POSTGRES_PASSWORD: CHANGE_ME_STAGING_DB_PASSWORD - volumes: - - postgres_staging_data:/var/lib/postgresql/data + - name: Prepare staging env + run: | + cp /var/lib/xiaoxia-saas-staging/.env /var/lib/xiaoxia-saas-staging/repo/.env - redis: - image: redis:7 - restart: unless-stopped + - name: Build staging images + run: | + docker build \ + -t xiaoxia-saas-api:${{ github.sha }} \ + -t xiaoxia-saas-api:staging \ + -f /var/lib/xiaoxia-saas-staging/repo/infra/docker/api.Dockerfile \ + /var/lib/xiaoxia-saas-staging/repo + docker build \ + -t xiaoxia-saas-worker:${{ github.sha }} \ + -t xiaoxia-saas-worker:staging \ + -f /var/lib/xiaoxia-saas-staging/repo/infra/docker/worker.Dockerfile \ + /var/lib/xiaoxia-saas-staging/repo + + - name: Deploy staging containers + run: | + cd /var/lib/xiaoxia-saas-staging/repo/infra/docker + API_IMAGE=xiaoxia-saas-api:staging \ + WORKER_IMAGE=xiaoxia-saas-worker:staging \ + docker compose up -d postgres redis api worker + docker compose ps + + - name: Verify staging health + run: | + for i in $(seq 1 30); do + if curl -fsS http://127.0.0.1:8000/api/v1/health; then + exit 0 + fi + sleep 2 + done + exit 1 -volumes: - postgres_staging_data: -COMPOSE - - docker-compose up -d - rm -f /tmp/api-image.tar.gz /tmp/worker-image.tar.gz - - echo "✅ Staging deployment completed" - deploy-production: + name: Deploy Production runs-on: ubuntu-latest - needs: build if: startsWith(github.ref, 'refs/tags/v') - + steps: - name: Checkout code uses: actions/checkout@v3 - - - name: Deploy to production + + - name: Sync code to production workspace run: | - # Load Docker images - docker load < /tmp/api-image.tar.gz - docker load < /tmp/worker-image.tar.gz - - # Prepare production directory - mkdir -p /var/lib/xiaoxia-saas-production - cp .env.production /var/lib/xiaoxia-saas-production/.env - - # Tag as production version - docker tag xiaoxia-saas-api:${{ github.sha }} xiaoxia-saas-api:${{ github.ref_name }} - docker tag xiaoxia-saas-worker:${{ github.sha }} xiaoxia-saas-worker:${{ github.ref_name }} - docker tag xiaoxia-saas-api:${{ github.sha }} xiaoxia-saas-api:latest - docker tag xiaoxia-saas-worker:${{ github.sha }} xiaoxia-saas-worker:latest - - # Deploy with production env - cd /var/lib/xiaoxia-saas-production - cat > docker-compose.yml << 'COMPOSE' -version: '3.9' -services: - api: - image: xiaoxia-saas-api:latest - restart: unless-stopped - env_file: - - ./.env - ports: - - "8000:8000" - depends_on: - - postgres - - redis + mkdir -p /var/lib/xiaoxia-saas-production/repo + rsync -a --delete --exclude '.git' ./ /var/lib/xiaoxia-saas-production/repo/ - worker: - image: xiaoxia-saas-worker:latest - restart: unless-stopped - env_file: - - ./.env - depends_on: - - redis - - postgres + - name: Verify production env file + run: | + test -f /var/lib/xiaoxia-saas-production/.env - postgres: - image: postgres:16 - restart: unless-stopped - environment: - POSTGRES_DB: xiaoxia_saas_production - POSTGRES_USER: postgres - POSTGRES_PASSWORD: CHANGE_ME_PRODUCTION_DB_PASSWORD - volumes: - - postgres_production_data:/var/lib/postgresql/data + - name: Prepare production env + run: | + cp /var/lib/xiaoxia-saas-production/.env /var/lib/xiaoxia-saas-production/repo/.env - redis: - image: redis:7 - restart: unless-stopped + - name: Build production images + run: | + docker build \ + -t xiaoxia-saas-api:${{ github.sha }} \ + -t xiaoxia-saas-api:${{ github.ref_name }} \ + -t xiaoxia-saas-api:latest \ + -f /var/lib/xiaoxia-saas-production/repo/infra/docker/api.Dockerfile \ + /var/lib/xiaoxia-saas-production/repo + docker build \ + -t xiaoxia-saas-worker:${{ github.sha }} \ + -t xiaoxia-saas-worker:${{ github.ref_name }} \ + -t xiaoxia-saas-worker:latest \ + -f /var/lib/xiaoxia-saas-production/repo/infra/docker/worker.Dockerfile \ + /var/lib/xiaoxia-saas-production/repo -volumes: - postgres_production_data: -COMPOSE - - docker-compose up -d - rm -f /tmp/api-image.tar.gz /tmp/worker-image.tar.gz - - echo "✅ Production deployment completed: ${{ github.ref_name }}" + - name: Deploy production containers + run: | + cd /var/lib/xiaoxia-saas-production/repo/infra/docker + API_IMAGE=xiaoxia-saas-api:latest \ + WORKER_IMAGE=xiaoxia-saas-worker:latest \ + docker compose up -d postgres redis api worker + docker compose ps + + - name: Verify production health + run: | + for i in $(seq 1 30); do + if curl -fsS http://127.0.0.1:8000/api/v1/health; then + exit 0 + fi + sleep 2 + done + exit 1 diff --git a/docs/CI-CD.md b/docs/CI-CD.md index 39f3fdc6f..57b94640e 100644 --- a/docs/CI-CD.md +++ b/docs/CI-CD.md @@ -2,137 +2,102 @@ ## Gitea Actions -本项目使用 Gitea Actions 实现 CI/CD 流水线。 +本项目使用 Gitea Actions + 本机 act_runner 实现 CI/CD。 ### 工作流文件 **1. `.gitea/workflows/tests.yml` - 自动化测试** 触发条件: -- 每次 push 到 main 分支 +- 每次 push 到 `main` - 每次创建 Pull Request 包含任务: - `test` - 运行集成测试,生成覆盖率报告 -- `lint` - 代码质量检查(Black、Flake8、MyPy) +- `lint` - 运行 Black / Flake8 / MyPy **2. `.gitea/workflows/deploy.yml` - 自动化部署** 触发条件: -- push 到 main 分支 → 部署到 staging 环境 -- 创建 tag (v*) → 部署到 production 环境 +- push 到 `main` → 部署到 staging +- push tag `v*` → 部署到 production -当前状态:占位,待补充真实部署脚本 +实际行为: +- runner 在部署主机本机执行 workflow +- workflow 将仓库同步到 `/var/lib/xiaoxia-saas-staging/repo` 或 `/var/lib/xiaoxia-saas-production/repo` +- 读取服务器本地真实 `.env` +- 本机构建 API / Worker 镜像 +- 使用 `infra/docker/compose.yml` 启动 `postgres` / `redis` / `api` / `worker` +- 部署后用 `/api/v1/health` 做健康校验 + +--- + +## 部署目录约定 + +### Staging +- 环境根目录:`/var/lib/xiaoxia-saas-staging` +- 真实环境文件:`/var/lib/xiaoxia-saas-staging/.env` +- Actions 同步代码目录:`/var/lib/xiaoxia-saas-staging/repo` + +### Production +- 环境根目录:`/var/lib/xiaoxia-saas-production` +- 真实环境文件:`/var/lib/xiaoxia-saas-production/.env` +- Actions 同步代码目录:`/var/lib/xiaoxia-saas-production/repo` --- ## 本地验证 -在推送前,可以本地运行验证: +推送前建议先跑: ### 运行测试 ```bash pytest tests/integration/ -v --cov=packages --cov=apps --cov-report=html ``` -### 代码格式化 +### 代码格式化检查 ```bash -black packages/ apps/ tests/ +black --check packages/ apps/ tests/ ``` -### 代码检查 +### 静态检查 ```bash -# Flake8 flake8 packages/ apps/ tests/ --max-line-length=120 --extend-ignore=E203,W503 - -# MyPy mypy packages/ apps/ --ignore-missing-imports ``` -### 排序 imports -```bash -isort packages/ apps/ tests/ -``` - --- -## Gitea Actions 配置 +## 当前已验证结论 -### 前提条件 - -1. Gitea 服务器需要启用 Actions 功能 -2. 需要配置 Actions Runner - -### 启用步骤 - -**在 Gitea 服务器上**: - -1. 编辑 `/etc/gitea/app.ini`(或对应配置文件): -```ini -[actions] -ENABLED = true -``` - -2. 重启 Gitea: -```bash -systemctl restart gitea -``` - -3. 安装 Actions Runner: -```bash -# 下载 act_runner -wget https://dl.gitea.com/act_runner/latest/act_runner-linux-amd64 -chmod +x act_runner-linux-amd64 -mv act_runner-linux-amd64 /usr/local/bin/act_runner - -# 注册 runner -act_runner register --instance http://your-gitea-server --token YOUR_RUNNER_TOKEN - -# 运行 runner -act_runner daemon -``` - -4. 在仓库设置中启用 Actions - ---- - -## 验证 CI/CD - -推送代码后,在 Gitea 仓库页面查看: -- Actions 标签页 -- 查看工作流运行状态 -- 查看测试结果和覆盖率报告 +- Gitea Actions 已启用 +- `act_runner` 已注册并持续运行 +- staging 可手工部署并已完成真实业务闭环验证 +- 当前 CI/CD 的关键目标是让 Gitea push 后自动完成同机部署,而不是只保留占位 YAML --- ## 故障排查 -### Actions 未触发 -- 检查 Gitea 是否启用 Actions -- 检查工作流文件路径是否正确(`.gitea/workflows/`) -- 检查 YAML 语法是否正确 +### Actions 触发了但 checkout 失败 +优先检查 runner 能否从 job 容器访问 Gitea 实例地址。 -### 测试失败 -- 查看 Actions 日志 -- 本地运行 `pytest tests/integration/ -v` -- 检查依赖是否完整 +### Deploy 成功但业务链不通 +优先检查: +- `/var/lib/xiaoxia-saas-staging/.env` +- `MINIO_ENDPOINT` +- `DATABASE_URL` +- worker 日志中的 Celery 任务消费情况 -### Linting 失败 -- 本地运行 `black --check packages/` -- 本地运行 `flake8 packages/` -- 修复后重新推送 - ---- - -## 未来扩展 - -- [ ] 添加性能测试 -- [ ] 添加安全扫描 -- [ ] 添加 Docker 镜像构建 -- [ ] 添加自动化部署脚本 -- [ ] 添加 Slack/钉钉通知 +### 健康检查失败 +查看: +```bash +docker compose ps +docker compose logs api --tail=200 +docker compose logs worker --tail=200 +``` --- **最后更新**: 2026-06-15 -**状态**: 配置完成,待 Gitea Actions 启用 +**状态**: CI/CD 已接入真实主机部署模型,待 push 后持续验证稳定性 diff --git a/infra/docker/compose.yml b/infra/docker/compose.yml index 802353bd8..bcb0f2478 100644 --- a/infra/docker/compose.yml +++ b/infra/docker/compose.yml @@ -1,4 +1,3 @@ -version: '3.9' services: web: image: node:20 @@ -12,7 +11,7 @@ services: - api api: - image: xiaoxia-saas-api:dev + image: ${API_IMAGE:-xiaoxia-saas-api:dev} build: context: ../.. dockerfile: infra/docker/api.Dockerfile @@ -27,7 +26,7 @@ services: - redis worker: - image: xiaoxia-saas-worker:dev + image: ${WORKER_IMAGE:-xiaoxia-saas-worker:dev} build: context: ../.. dockerfile: infra/docker/worker.Dockerfile