From b75a7ada750b78c4e1fa5d23f576ca43597e34f5 Mon Sep 17 00:00:00 2001 From: Wang Zhuoxuan Date: Sat, 18 Apr 2026 04:23:16 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20CI=20=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=96=87=E6=A1=A3=E8=87=B3=20v5.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同步实际部署配置变更: - Docker Compose 使用 network_mode: host 避免 VPC 冲突 - Act Runner config 补充 options + valid_volumes 挂载配置 - 移除 systemd 不必要的 BindPaths - CI health check 改用 bun fetch - 新增 Docker bridge/VPC 冲突和 health check 故障排查 --- docs/ci-deployment-guide.md | 86 +++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/docs/ci-deployment-guide.md b/docs/ci-deployment-guide.md index b950717..d800814 100644 --- a/docs/ci-deployment-guide.md +++ b/docs/ci-deployment-guide.md @@ -361,6 +361,11 @@ runner: container: # 容器使用宿主机网络(解决容器无法访问 127.0.0.1:3200 Gitea 的问题) network: "host" + # 挂载宿主机目录到 job 容器(CI deploy 步骤需要读取 docker-compose.yml) + options: "-v /opt/duoqi-api:/opt/duoqi-api" + # 允许挂载的 volume 白名单 + valid_volumes: + - /opt/duoqi-api # 不强制每次拉取镜像(国内网络下减少失败风险) force_pull: false ``` @@ -379,9 +384,6 @@ ExecStart=/usr/local/bin/act_runner daemon --config /opt/act-runner/config.yaml Restart=always Environment=HOME=/root -# 关键:挂载 Docker socket,让 job 容器能访问宿主机的 Docker daemon -BindPaths=/var/run/docker.sock:/var/run/docker.sock - [Install] WantedBy=multi-user.target EOF @@ -395,6 +397,11 @@ systemctl start act-runner systemctl status act-runner ``` +> **注意**:act_runner 是宿主机原生运行的二进制,不是容器。它本身已有完整的文件系统和网络访问权限。 +> - **不需要** `BindPaths` 挂载 Docker socket(宿主机进程可直接访问) +> - **不需要** `BindPaths` 挂载 `/opt/duoqi-api`(同上) +> - job 容器需要访问宿主机目录,通过 `config.yaml` 中的 `container.options` 和 `valid_volumes` 配置 + ### 环境隔离策略 #### RDS 数据库隔离 @@ -472,21 +479,22 @@ LOG_LEVEL=debug **服务器 compose 文件** `/opt/duoqi-api/docker-compose.yml`: +> 代码库中对应文件为 `docker-compose.prod.yml`,部署时手动重命名为 `docker-compose.yml`。 + ```yaml -version: '3.8' +# 使用 host 网络模式,避免 Docker bridge 子网与阿里云 VPC 内网 IP 段冲突 services: # ===== 生产环境 ===== api-prod: build: - context: /opt/gitea/data/git/repositories/admin/duoqi-api.git + context: . dockerfile: Dockerfile image: duoqi-api:prod container_name: duoqi-api-prod restart: unless-stopped + network_mode: host env_file: .env.prod - ports: - - "3000:3000" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/health"] interval: 30s @@ -503,17 +511,16 @@ services: limits: memory: 400M - # ===== 测试环境(按需启停) ===== + # ===== 测试环境(Docker profiles 按需启停) ===== api-test: build: - context: /opt/gitea/data/git/repositories/admin/duoqi-api.git + context: . dockerfile: Dockerfile image: duoqi-api:test container_name: duoqi-api-test - restart: "no" # 不自动重启,手动控制 + restart: "no" + network_mode: host env_file: .env.test - ports: - - "3001:3001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/health"] interval: 30s @@ -530,7 +537,7 @@ services: limits: memory: 300M profiles: - - test # 使用 profiles 按需启停 + - test ``` **启停命令:** @@ -621,9 +628,11 @@ git push origin main | 生产部署手动确认 | 防止误操作,确保人工验证后才上线 | | 使用 Gitea Actions | 兼容 GitHub Actions 语法,学习成本低 | | Runner 使用 `network: host` | 容器共享宿主机网络,解决容器无法访问 Gitea 的问题 | +| API 容器使用 `network_mode: host` | 避免 Docker bridge 默认子网(172.x.0.0/16)与阿里云 VPC 内网 IP 段冲突 | | Runner 使用 `github_mirror` | 从 gitea.com 镜像拉取 Actions,解决国内无法访问 GitHub 的问题 | | 自定义 Runner 镜像(bun + git + docker CLI) | 避免 checkout REST API 不兼容,支持 CI 中执行 docker 命令 | -| Runner 挂载 Docker socket | Job 容器通过 socket 访问宿主机 Docker daemon,执行构建操作 | +| Runner config 的 `options` + `valid_volumes` | 让 job 容器能挂载宿主机的 `/opt/duoqi-api` 目录,读取 docker-compose.yml | +| CI health check 使用 `bun -e "fetch(...)"` | runner 镜像未安装 curl,用 bun 内置 fetch API 做 HTTP 健康检查 | | 固定 Bun 版本(1.3) | 确保 CI 环境可复现,避免 latest 版本变化导致意外失败 | ### 部署操作 @@ -840,11 +849,10 @@ services: # Phase 2: 多实例 docker-compose.yml # API 服务器上的配置 -version: '3.8' - services: api: image: your-registry/duoqi-api:latest + network_mode: host deploy: replicas: 2 # 运行 2 个实例 resources: @@ -1036,6 +1044,48 @@ mysql -h your-rds-endpoint -u duoqi_prod -p -e "SELECT 1;" # 阿里云 RDS 控制台 → 数据安全性 → 白名单设置 ``` +#### 7. Docker bridge 网络与 VPC 内网冲突 + +> **症状**:服务器无法连接 RDS(或 VPC 内其他服务),ping 显示源 IP 为 `172.x.0.1`(Docker 网桥 IP)而非宿主机内网 IP。 + +```bash +# 查看路由表,检查是否有 Docker 网桥路由劫持了 VPC 流量 +route -n +# 如果看到类似以下行,说明 Docker bridge 子网与 RDS IP 段冲突: +# 172.23.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-xxxxxx + +# 查看哪个 Docker 网络创建了冲突子网 +docker network ls +docker network inspect + +# 解决方案 1:使用 network_mode: host(推荐,已在本方案中采用) +# 在 docker-compose.yml 中为服务添加 network_mode: host +# 这样不会创建 Docker bridge 网络,从根本上避免 IP 段冲突 + +# 解决方案 2:指定不冲突的子网 +# docker network create --subnet=192.168.200.0/24 my-network +``` + +#### 8. CI health check 失败 + +```bash +# 检查 health 路径是否正确(health 路由注册时无 /v1 前缀) +# 正确:/health 错误:/v1/health + +# 检查容器是否在运行 +docker ps -a --filter name=duoqi-api-prod + +# 检查端口是否在监听(host 网络模式下直接看宿主机端口) +ss -tlnp | grep 3000 + +# 查看容器日志 +docker logs duoqi-api-prod --tail 50 + +# 注意:CI health check 使用 bun -e "fetch(...)" 而非 curl +# 如果 bun 的 promise 处理有问题,使用 top-level await: +# bun -e "try{const r=await fetch('http://localhost:3000/health');process.exit(r.ok?0:1)}catch{process.exit(1)}" +``` + ### 回滚操作 ```bash @@ -1113,6 +1163,6 @@ docker compose up -d api-prod --- -**文档版本**: v5.2.0 (双分支工作流 + 国内网络适配 + Docker 执行器完善) -**最后更新**: 2026-04-17 +**文档版本**: v5.3.0 (host 网络模式 + Act Runner 挂载配置 + 故障排查更新) +**最后更新**: 2026-04-18 **维护者**: Duoqi Team