# Duoqi API 部署与持续集成方案 > 基于 Gitea + 阿里云轻量应用服务器 (Alibaba Cloud Linux 3) 的私有化部署方案 ## 目录 - [架构概览](#架构概览) - [Phase 1: 单服务器方案(当前)](#phase-1-单服务器方案当前) - [资源规划](#资源规划) - [服务器初始化](#服务器初始化) - [Gitea 安装与配置](#gitea-安装与配置) - [环境隔离策略](#环境隔离策略) - [CI/CD 流程](#cicd-流程) - [部署操作](#部署操作) - [Nginx 配置](#nginx-配置) - [Phase 2: 多服务器扩展(未来)](#phase-2-多服务器扩展未来) - [架构演进](#架构演进) - [私有镜像仓库](#私有镜像仓库) - [负载均衡与水平扩展](#负载均衡与水平扩展) - [运维管理](#运维管理) - [故障排查](#故障排查) - [附录](#附录) --- ## 架构概览 ### 为什么选择 Gitea 而不是 GitLab | 对比项 | Gitea | GitLab CE | |--------|-------|-----------| | 最低内存 | ~200MB | ~4GB | | 安装复杂度 | 单二进制文件 | 需要多组件 | | CI/CD | Gitea Actions(兼容 GitHub Actions 语法) | GitLab CI/CD | | 容器镜像仓库 | 内置(可选) | 内置 | | 适合场景 | 小团队、资源有限 | 大团队、功能全面 | | **2C/2G 可行性** | **✅ 完全可行** | **❌ 内存不足** | ### 单服务器资源分配(2C/2G) ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 阿里云轻量应用服务器 (2C/2G) │ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Nginx 反向代理 (:80/:443 ← 唯一对外入口) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌────────────────────────┐│ │ │ │ │ api.duoqi.me│ │test-api. │ │ git.duoqi.me ││ │ │ │ │ → :3000 prod │ │duoqi.me │ │ → :3200 Gitea (IP限制) ││ │ │ │ │ │ │ → :3001 test │ │ ││ │ │ │ └──────────────┘ └──────────────┘ └────────────────────────┘│ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────────┐ │ │ │ duoqi-api │ │ duoqi-api │ │ Gitea + Act Runner │ │ │ │ (prod) │ │ (test) │ │ 代码托管 + CI/CD │ │ │ │ 127.0.0.1 │ │ 127.0.0.1 │ │ 127.0.0.1:3200 │ │ │ │ :3000 │ │ :3001 │ │ ~200MB │ │ │ │ ~300MB │ │ ~200MB │ └──────────────────────────┘ │ │ └─────────────┘ └──────────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ 阿里云 RDS MySQL (外置,仅内网可达) │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ duoqi_prod │ │ duoqi_test │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ └───────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` **内存预算:** | 组件 | 预估占用 | 说明 | |------|----------|------| | OS + 系统 | ~200MB | Alibaba Cloud Linux 3 | | Docker | ~150MB | Docker Daemon | | Gitea | ~200MB | 含 Act Runner | | Nginx | ~50MB | 反向代理 | | duoqi-api (prod) | ~300MB | 生产容器 | | duoqi-api (test) | ~200MB | 测试容器(按需启停) | | **合计** | **~1.1GB** | **剩余 ~900MB 缓冲** | --- ## Phase 1: 单服务器方案(当前) ### 资源规划 | 资源 | 配置 | 用途 | |------|------|------| | 轻量应用服务器 | 2C/2G/40GB SSD | Gitea + Docker + Nginx | | 阿里云 RDS MySQL | 1C/1G 基础版 | duoqi_prod + duoqi_test | | 域名 + SSL | api.duoqi.me | 生产环境入口 | ### 服务器初始化 > 系统选择 **Alibaba Cloud Linux 3**(阿里云官方优化内核,内存占用更低,与 RDS 兼容性更好) ```bash # SSH 登录 ssh root@your-server-ip # 1. 更新系统 dnf update -y # 2. 安装基础工具 dnf install -y curl git nginx certbot python3-certbot-nginx # 3. 安装 Docker(Alibaba Cloud Linux 内置 Docker 源) dnf install -y docker docker-compose systemctl enable --now docker # 4. 配置防火墙(firewalld) # 所有服务通过 Nginx 反向代理,只需开放 22/80/443 systemctl enable --now firewalld firewall-cmd --permanent --add-service=ssh firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload # 5. 创建项目目录 mkdir -p /opt/duoqi-api mkdir -p /opt/gitea mkdir -p /opt/backups # 6. 验证 cat /etc/os-release # 确认 Alibaba Cloud Linux docker --version nginx -v ``` ### Gitea 安装与配置 #### 方式一:二进制安装(推荐,更省内存) > Gitea 是单个 Go 二进制文件,直接运行在宿主机上比 Docker 方式省 ~50MB 内存,且 systemd 管理更可靠。 > 在 2C/2G 服务器上,省下的每一 MB 都有意义。 ```bash # 下载 Gitea wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/1.22/gitea-1.22-linux-amd64 chmod +x /usr/local/bin/gitea # 创建用户和目录 groupadd --system git useradd --system --gid git --shell /bin/bash -m git mkdir -p /var/lib/gitea/{custom,data,log} chown -R git:git /var/lib/gitea mkdir -p /etc/gitea chown git:git /etc/gitea # 创建 systemd 服务 cat > /etc/systemd/system/gitea.service << 'EOF' [Unit] Description=Gitea After=network.target [Service] User=git WorkingDirectory=/var/lib/gitea ExecStart=/usr/local/bin/gitea web -c /etc/gitea/app.ini --port 3200 --http-addr 127.0.0.1 Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea [Install] WantedBy=multi-user.target EOF # 启动 systemctl enable gitea systemctl start gitea # 等待 Gitea 生成默认配置文件 sleep 3 systemctl stop gitea ``` **配置反向代理适配(关键步骤):** > Gitea 需要知道自己对外是 `https://git.duoqi.me`,否则 Git clone URL 和 Web UI 链接会指向 `127.0.0.1:3200`。 ```bash # 编辑 Gitea 配置文件 cat >> /etc/gitea/app.ini << 'EOF' [server] DOMAIN = git.duoqi.me ROOT_URL = https://git.duoqi.me/ HTTP_ADDR = 127.0.0.1 HTTP_PORT = 3200 SSH_DOMAIN = git.duoqi.me SSH_PORT = 22 SSH_LISTEN_PORT = 22 OFFLINE_MODE = true ; 禁用 Gravatar 等外部服务,加快页面加载 [security] INSTALL_LOCK = true ; 已完成安装,禁止再次访问安装页面 [service] REGISTER_EMAIL_CONFIRM = false ; 按需开启 DISABLE_REGISTRATION = true ; 禁止公开注册,仅管理员创建账号 [other] SHOW_FOOTER_VERSION = false ; 隐藏版本号,减少信息泄露 EOF # 修正权限 chown git:git /etc/gitea/app.ini chmod 640 /etc/gitea/app.ini # 启动 systemctl start gitea ``` #### 方式二:Docker 部署(备选) ```bash cat > /opt/gitea/docker-compose.yml << 'EOF' version: '3.8' services: gitea: image: gitea/gitea:latest container_name: gitea restart: unless-stopped environment: - USER_UID=1000 - USER_GID=1000 - GITEA__server__DOMAIN=git.duoqi.me - GITEA__server__ROOT_URL=https://git.duoqi.me/ - GITEA__server__HTTP_ADDR=127.0.0.1 - GITEA__server__HTTP_PORT=3200 - GITEA__server__SSH_DOMAIN=git.duoqi.me volumes: - ./data:/data - /etc/localtime:/etc/localtime:ro network_mode: host ; 需要绑定 127.0.0.1,使用 host 网络 logging: driver: "json-file" options: max-size: "10m" max-file: "3" EOF cd /opt/gitea && docker-compose up -d ``` > **注意**: Docker 方式会额外占用 ~50MB 内存(容器运行时开销),仅当需要快速试用或测试时使用。 #### Gitea 初始化配置 ``` 1. 浏览器访问 https://git.duoqi.me(通过 Nginx 反向代理) 首次启动时也可临时访问 http://127.0.0.1:3200 2. 首次配置(安装页面): - 数据库:SQLite3(默认) - 服务器域名:git.duoqi.me - Gitea HTTP 监听端口:3200 - SSH 服务端口:22 - 管理员账号:创建 admin 用户 3. 创建仓库:duoqi-api 4. 推送代码(HTTP): git remote add gitea https://git.duoqi.me/admin/duoqi-api.git git push gitea main git checkout -b develop git push gitea develop 或使用 SSH: git remote add gitea git@git.duoqi.me:admin/duoqi-api.git git push gitea main git checkout -b develop git push gitea develop ``` #### 安装 Act Runner(CI/CD 执行器) ```bash # 下载 Act Runner wget -O /usr/local/bin/act_runner https://gitea.com/gitea/act_runner/releases/latest/download/act_runner-linux-amd64 chmod +x /usr/local/bin/act_runner # 在 Gitea Web UI 中生成 Token: # Settings → Actions → Runners → Create new Runner → 复制 Token # 创建专用工作目录(register 和 daemon 必须在同一目录) mkdir -p /opt/act-runner # 注册 Runner cd /opt/act-runner && act_runner register \ --instance http://localhost:3200 \ --token YOUR_RUNNER_TOKEN \ --name duoqi-runner \ --labels ubuntu-latest:docker://oven/bun:latest # 创建 systemd 服务 cat > /etc/systemd/system/act-runner.service << 'EOF' [Unit] Description=Gitea Act Runner After=docker.service [Service] WorkingDirectory=/opt/act-runner ExecStart=/usr/local/bin/act_runner daemon Restart=always Environment=HOME=/root [Install] WantedBy=multi-user.target EOF # 启动 systemctl daemon-reload systemctl enable act-runner systemctl start act-runner # 验证:确认 active (running),且 Gitea Web UI 中 Runner 显示在线 systemctl status act-runner ``` ### 环境隔离策略 #### RDS 数据库隔离 ```sql -- 连接到 RDS mysql -h your-rds-endpoint -u root -p -- 创建生产库 CREATE DATABASE duoqi_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建测试库 CREATE DATABASE duoqi_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建用户并授权 CREATE USER 'duoqi_prod'@'%' IDENTIFIED BY 'prod-password'; GRANT ALL PRIVILEGES ON duoqi_prod.* TO 'duoqi_prod'@'%'; CREATE USER 'duoqi_test'@'%' IDENTIFIED BY 'test-password'; GRANT ALL PRIVILEGES ON duoqi_test.* TO 'duoqi_test'@'%'; FLUSH PRIVILEGES; ``` #### 环境配置文件 **密钥生成**(在配置环境变量之前): ```bash # 生成 JWT_SECRET(用于签名和验证用户 JWT) openssl rand -base64 32 # 生成 ADMIN_TOKEN(管理后台认证令牌) openssl rand -base64 32 # 或使用 Node.js 生成: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))" ``` > **安全提示**: > - `JWT_SECRET` 必须至少 32 字符(代码中有强制校验) > - 生产环境和测试环境必须使用不同的密钥 > - 密钥生成后应妥善保管,不要提交到 Git 仓库 > - 可在任意服务器生成,关键是通过安全渠道传输到目标环境 **生产环境** `/opt/duoqi-api/.env.prod`: ```env DATABASE_URL=mysql://duoqi_prod:prod-password@your-rds-endpoint:3306/duoqi_prod JWT_SECRET=prod-super-secret-jwt-key # 替换为生成的密钥 JWT_EXPIRES_IN=1h JWT_REFRESH_EXPIRES_IN=30d ADMIN_TOKEN=prod-admin-token # 替换为生成的密钥 PORT=3000 NODE_ENV=production LOG_LEVEL=warn # ... 其他生产环境变量 ``` **测试环境** `/opt/duoqi-api/.env.test`: ```env DATABASE_URL=mysql://duoqi_test:test-password@your-rds-endpoint:3306/duoqi_test JWT_SECRET=test-secret-key # 与生产环境不同 JWT_EXPIRES_IN=1h JWT_REFRESH_EXPIRES_IN=30d ADMIN_TOKEN=test-admin-token # 与生产环境不同 PORT=3001 NODE_ENV=test LOG_LEVEL=debug # ... 其他测试环境变量(可使用测试用的华为、OSS配置) ``` #### Docker Compose 环境隔离 **服务器 compose 文件** `/opt/duoqi-api/docker-compose.yml`: ```yaml version: '3.8' services: # ===== 生产环境 ===== api-prod: build: context: /opt/gitea/data/git/repositories/admin/duoqi-api.git dockerfile: Dockerfile image: duoqi-api:prod container_name: duoqi-api-prod restart: unless-stopped env_file: .env.prod ports: - "3000:3000" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s logging: driver: "json-file" options: max-size: "10m" max-file: "3" deploy: resources: limits: memory: 400M # ===== 测试环境(按需启停) ===== api-test: build: context: /opt/gitea/data/git/repositories/admin/duoqi-api.git dockerfile: Dockerfile image: duoqi-api:test container_name: duoqi-api-test restart: "no" # 不自动重启,手动控制 env_file: .env.test ports: - "3001:3001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s logging: driver: "json-file" options: max-size: "5m" max-file: "2" deploy: resources: limits: memory: 300M profiles: - test # 使用 profiles 按需启停 ``` **启停命令:** ```bash # 只启动生产环境(默认) docker-compose up -d # 启动生产 + 测试环境 docker-compose --profile test up -d # 停止测试环境(释放内存) docker-compose --profile test stop api-test # 重新构建并启动 docker-compose up -d --build api-prod docker-compose --profile test up -d --build api-test ``` ### CI/CD 流程 #### 双分支工作流 ``` develop 分支(开发测试) main 分支(生产发布) │ │ ▼ ▼ ┌───────────┐ ┌───────────┐ │ quality │ ← Lint + 类型检查 │ quality │ ← Lint + 类型检查 └─────┬─────┘ └─────┬─────┘ ▼ ▼ ┌───────────┐ ┌───────────┐ │ test │ ← 单元测试 + 覆盖率 │ test │ ← 单元测试 + 覆盖率 └─────┬─────┘ └─────┬─────┘ ▼ ▼ ┌────────────┐ ┌────────────┐ │ build-test │ ← 构建测试镜像 │ build-prod │ ← 构建生产镜像 └─────┬──────┘ └─────┬──────┘ ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ deploy-test │ ← 自动部署到测试 │ deploy-prod │ ← 手动确认后部署生产 └─────────────┘ └─────────────┘ ``` #### 日常开发流程 ```bash # 1. 在 develop 上开发 git checkout develop # ... 编写代码 ... git add . git commit -m "feat: 新功能描述" git push origin develop # → 自动触发:quality → test → build-test → deploy-test # 2. 在测试环境验证(http://test-api.duoqi.me) # 如果发现问题,继续在 develop 上修改并 push # 3. 测试通过,合并到 main 发布 git checkout main git merge develop git push origin main # → 自动触发:quality → test → build-prod # → 在 Gitea Web UI 手动确认 deploy-prod ``` #### 触发规则 | 事件 | quality | test | build | deploy | |------|---------|------|-------|--------| | push 到 `develop` | ✅ | ✅ | build-test | deploy-test(自动) | | push 到 `main` | ✅ | ✅ | build-prod | deploy-prod(**手动确认**) | > **注意**:`develop` 分支需要在 Gitea 仓库中手动创建: > ```bash > git checkout -b develop > git push origin develop > ``` #### 关键设计说明 | 设计决策 | 原因 | |---------|------| | 双分支隔离(develop + main) | develop 是试验场,main 是稳定版本,互不干扰 | | 不同分支构建不同镜像 | develop 只构建 test 镜像,main 只构建 prod 镜像,节省 2C/2G 服务器资源 | | 本地构建镜像,无外部仓库 | 单服务器不需要镜像中转,节省资源 | | 测试环境使用 Docker profiles | 按需启停,节省内存 | | 生产部署手动确认 | 防止误操作,确保人工验证后才上线 | | 使用 Gitea Actions | 兼容 GitHub Actions 语法,学习成本低 | ### 部署操作 #### 手动部署(首次或紧急) ```bash # SSH 登录服务器 ssh root@your-server-ip cd /opt/duoqi-api # 从 Gitea 拉取最新代码 git -C /opt/duoqi-api/repo pull # 如果用 git clone 方式 # 或使用部署脚本 bash scripts/deploy.sh prod ``` #### 使用部署脚本 ```bash # 部署到生产环境 bash scripts/deploy.sh prod # 部署到测试环境 bash scripts/deploy.sh test # 停止测试环境 bash scripts/deploy.sh test-stop # 查看状态 bash scripts/deploy.sh status # 回滚 bash scripts/deploy.sh rollback prod ``` ### Nginx 配置 > 所有服务通过 Nginx 统一入口,后端端口仅绑定 localhost,防火墙只开 22/80/443。 ```bash # 生产环境 API cat > /etc/nginx/conf.d/duoqi-api.conf << 'EOF' server { listen 80; server_name api.duoqi.me; location / { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF # 测试环境 API(仅限内部访问) cat > /etc/nginx/conf.d/duoqi-api-test.conf << 'EOF' server { listen 80; server_name test-api.duoqi.me; # 限制访问 IP(开发团队办公网络) # allow 123.56.78.90; # deny all; location / { proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF # Gitea 代码仓库(限制访问 IP,仅团队可访问) cat > /etc/nginx/conf.d/gitea.conf << 'EOF' server { listen 80; server_name git.duoqi.me; # 限制访问 IP(开发团队办公网络) # allow 123.56.78.90; # deny all; location / { proxy_pass http://127.0.0.1:3200; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Gitea 需要较大的请求体(git push) client_max_body_size 100M; } } EOF # 验证并生效 nginx -t systemctl enable --now nginx systemctl reload nginx ``` #### 配置 HTTPS ```bash # 为三个域名统一申请证书 certbot --nginx -d api.duoqi.me -d test-api.duoqi.me -d git.duoqi.me # 自动续期验证 certbot renew --dry-run ``` > [!NOTE] > > 在子域名还没有配置解析的前提下,会影响证书的签发。后期如果新增子域名,并且需要同一张证书时,可以通过`--expand`参数进行申请。 ```bash # 方案1:先申请已就绪的子域名 sudo certbot --nginx -d example.com -d www.example.com # 后续子域名就绪后,再扩容证书 sudo certbot --nginx --expand \ -d example.com -d www.example.com -d api.example.com -d blog.example.com ``` ##### 常见错误 ```bash # ❌ 错误:只写新增域名,会导致原有域名被移除! sudo certbot --nginx --expand -d api.example.com -d blog.example.com # ✅ 正确:列出所有域名(原有 + 新增) sudo certbot --nginx --expand \ -d example.com -d www.example.com -d api.example.com -d blog.example.com ``` --- ## Phase 2: 多服务器扩展(未来) ### 架构演进 ``` Phase 1 (当前) Phase 2 (扩展后) ┌──────────────┐ ┌─────────────────────────────────┐ │ 单台服务器 │ │ 负载均衡 (SLB/Nginx) │ │ │ │ api.duoqi.me → 443/80 │ │ Gitea │ └──────────┬──────────────────────┘ │ duoqi-api │ ──────▶ │ │ duoqi-api │ ┌──────────┴──────────┐ │ (prod+test) │ │ │ │ Nginx │ ┌────┴────┐ ┌─────┴────┐ └──────────────┘ │ API-1 │ │ API-2 │ │ (prod) │ │ (prod) │ ┌──────────────┐ └─────────┘ └──────────┘ │ RDS MySQL │ ┌─────────────┐ ┌──────────────┐ │ duoqi_prod │ │ CI/CD 服务器 │ │ 测试服务器 │ │ duoqi_test │ │ Gitea │ │ duoqi-api │ └──────────────┘ │ Harbor 镜像 │ │ (test) │ └─────────────┘ └──────────────┘ ``` ### 扩展触发条件 当出现以下情况时,考虑从 Phase 1 升级到 Phase 2: | 指标 | Phase 1 上限 | Phase 2 起步 | |------|-------------|-------------| | 日活用户 | ~1,000 | >1,000 | | 内存使用率 | 持续 >80% | — | | CPU 使用率 | 持续 >70% | — | | 需要独立测试服务器 | 否 | 是 | | 需要多实例高可用 | 否 | 是 | ### 私有镜像仓库 多服务器场景下需要镜像仓库统一分发: **方案一:Gitea 内置 Container Registry(推荐)** ``` # 在 Gitea 的 app.ini 中启用 [packages] ENABLED = true STORAGE_TYPE = local # 推送镜像 docker build -t your-server-ip:3200/admin/duoqi-api:latest . docker push your-server-ip:3200/admin/duoqi-api:latest ``` **方案二:Harbor(大规模场景)** ```yaml # docker-compose.harbor.yml # 需要独立服务器或至少 4GB 内存 services: harbor: image: goharbor/harbor:latest # ... Harbor 企业级镜像仓库 ``` ### 负载均衡与水平扩展 ```yaml # Phase 2: 多实例 docker-compose.yml # API 服务器上的配置 version: '3.8' services: api: image: your-registry/duoqi-api:latest deploy: replicas: 2 # 运行 2 个实例 resources: limits: cpus: '1' memory: 512M env_file: .env.prod healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 15s timeout: 5s retries: 3 ``` **阿里云 SLB 配置:** ``` 1. 创建负载均衡实例 2. 添加后端服务器(API-1, API-2) 3. 配置健康检查路径:/health 4. 配置 SSL 证书 5. 域名 DNS 解析到 SLB 公网 IP ``` ### Phase 2 CI/CD 流程 ``` 推送代码 → Gitea Actions → 构建 + 推送到私有镜像仓库 │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ 部署到测试服务器 部署到 API-1 部署到 API-2 (自动) (手动/灰度) (手动/灰度) ``` --- ## 运维管理 ### 日常维护命令 ```bash # 查看所有容器状态 docker-compose ps # 查看生产日志 docker-compose logs -f api-prod # 查看测试日志 docker-compose -f docker-compose.yml --profile test logs -f api-test # 重启生产环境 docker-compose restart api-prod # 进入容器调试 docker-compose exec api-prod sh # 查看资源使用 docker stats --no-stream ``` ### 数据库管理 ```bash # 测试库重置(清空测试数据) mysql -h your-rds-endpoint -u duoqi_test -p -e "DROP DATABASE duoqi_test; CREATE DATABASE duoqi_test CHARACTER SET utf8mb4;" # 执行迁移 docker-compose exec api-prod npx drizzle-kit migrate # 导入种子数据到测试库 docker-compose --profile test exec api-test bun run db:seed # 备份生产库 mysqldump -h your-rds-endpoint -u duoqi_prod -p duoqi_prod > /opt/backups/duoqi_prod_$(date +%Y%m%d).sql ``` ### 备份策略 ```bash # 创建备份脚本 cat > /opt/backups/backup.sh << 'SCRIPT' #!/bin/bash set -e BACKUP_DIR="/opt/backups" DATE=$(date +%Y%m%d_%H%M%S) # 数据库备份 mysqldump -h your-rds-endpoint -u duoqi_prod -pyour-password duoqi_prod \ | gzip > "$BACKUP_DIR/db_prod_$DATE.sql.gz" # Gitea 仓库备份 sudo -u git gitea dump -c /etc/gitea/app.ini # 备份文件生成在当前目录:gitea-dump-*.zip # 保留最近 7 天的备份 find $BACKUP_DIR -name "*.gz" -mtime +7 -delete echo "[$DATE] Backup completed" SCRIPT chmod +x /opt/backups/backup.sh # 定时任务(每天凌晨 2 点) echo "0 2 * * * /opt/backups/backup.sh >> /opt/backups/backup.log 2>&1" | crontab - ``` --- ## 故障排查 ### 常见问题 #### 1. 内存不足 ```bash # 查看内存使用 free -h # 停止测试环境释放内存 docker-compose --profile test stop api-test # 清理 Docker 缓存 docker system prune -f # 查看 Docker 磁盘占用 docker system df ``` #### 2. 容器启动失败 ```bash # 查看退出日志 docker-compose logs api-prod # 检查环境变量 docker-compose config # 检查端口冲突 netstat -tlnp | grep -E '3000|3001' ``` #### 3. Gitea Runner 不可用 ```bash # 检查 Runner 状态 systemctl status act-runner # 重启 Runner systemctl restart act-runner # 查看日志 journalctl -u act-runner -f ``` #### 4. 数据库连接失败 ```bash # 从服务器测试 RDS 连通性 mysql -h your-rds-endpoint -u duoqi_prod -p -e "SELECT 1;" # 检查 RDS 白名单是否包含服务器 IP # 阿里云 RDS 控制台 → 数据安全性 → 白名单设置 ``` ### 回滚操作 ```bash # 查看本地镜像历史 docker images | grep duoqi-api # 回滚到上一个版本 cd /opt/duoqi-api docker-compose down api-prod # 修改 docker-compose.yml 使用指定版本镜像 docker-compose up -d api-prod ``` --- ## 附录 ### A. 完整目录结构(服务器端) ``` /opt/ ├── gitea/ # Gitea 代码托管 │ ├── docker-compose.yml │ └── data/ # Gitea 数据(仓库、配置) ├── duoqi-api/ # 应用部署 │ ├── docker-compose.yml # 包含 prod + test 配置 │ ├── .env.prod # 生产环境变量 │ ├── .env.test # 测试环境变量 │ ├── Dockerfile # 镜像构建 │ └── repo/ # Git 仓库(用于构建) ├── backups/ # 备份目录 │ ├── backup.sh │ └── *.sql.gz └── scripts/ # 运维脚本 └── deploy.sh ``` ### B. Gitea Actions 与 GitHub Actions 语法对照 | 特性 | GitHub Actions | Gitea Actions | |------|---------------|---------------| | 文件路径 | `.github/workflows/` | `.gitea/workflows/` | | 语法 | YAML | 相同(完全兼容) | | 触发条件 | `on: push` | 相同 | | Runner | GitHub 托管 | 自托管 Act Runner | | 镜像 | `runs-on: ubuntu-latest` | 相同,或自定义标签 | ### C. 安全建议 | 项目 | 建议 | |------|------| | SSH | 禁用密码登录,仅密钥认证 | | 防火墙 | firewalld 仅开放 22/80/443,后端端口全部绑定 localhost | | 测试环境 | 通过 Nginx 限制访问 IP | | 数据库 | 生产用户和测试用户严格分离权限 | | JWT | 生产与测试使用不同密钥 | | SSL | 生产环境必须启用 HTTPS | | 内核更新 | Alibaba Cloud Linux 安全补丁自动推送,及时更新 | ### D. Ubuntu 与 Alibaba Cloud Linux 命令速查 | 操作 | Ubuntu (apt) | Alibaba Cloud Linux (dnf) | |------|-------------|--------------------------| | 更新系统 | `apt update && apt upgrade -y` | `dnf update -y` | | 安装软件 | `apt install -y ` | `dnf install -y ` | | 安装 Docker | `curl -fsSL https://get.docker.com \| sh` | `dnf install -y docker` | | 防火墙 | `ufw allow 80/tcp` | `firewall-cmd --permanent --add-port=80/tcp && firewall-cmd --reload` | | 创建用户 | `adduser --system --group git` | `groupadd --system git && useradd --system --gid git git` | | Nginx 配置 | `/etc/nginx/sites-available/` | `/etc/nginx/conf.d/` | --- **文档版本**: v5.0.0 (双分支工作流) **最后更新**: 2026-04-16 **维护者**: Duoqi Team