docs: 更新 CI 部署文档至 v5.3.0
同步实际部署配置变更: - Docker Compose 使用 network_mode: host 避免 VPC 冲突 - Act Runner config 补充 options + valid_volumes 挂载配置 - 移除 systemd 不必要的 BindPaths - CI health check 改用 bun fetch - 新增 Docker bridge/VPC 冲突和 health check 故障排查
This commit is contained in:
parent
9d1f52d95b
commit
b75a7ada75
@ -361,6 +361,11 @@ runner:
|
|||||||
container:
|
container:
|
||||||
# 容器使用宿主机网络(解决容器无法访问 127.0.0.1:3200 Gitea 的问题)
|
# 容器使用宿主机网络(解决容器无法访问 127.0.0.1:3200 Gitea 的问题)
|
||||||
network: "host"
|
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
|
force_pull: false
|
||||||
```
|
```
|
||||||
@ -379,9 +384,6 @@ ExecStart=/usr/local/bin/act_runner daemon --config /opt/act-runner/config.yaml
|
|||||||
Restart=always
|
Restart=always
|
||||||
Environment=HOME=/root
|
Environment=HOME=/root
|
||||||
|
|
||||||
# 关键:挂载 Docker socket,让 job 容器能访问宿主机的 Docker daemon
|
|
||||||
BindPaths=/var/run/docker.sock:/var/run/docker.sock
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
@ -395,6 +397,11 @@ systemctl start act-runner
|
|||||||
systemctl status act-runner
|
systemctl status act-runner
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **注意**:act_runner 是宿主机原生运行的二进制,不是容器。它本身已有完整的文件系统和网络访问权限。
|
||||||
|
> - **不需要** `BindPaths` 挂载 Docker socket(宿主机进程可直接访问)
|
||||||
|
> - **不需要** `BindPaths` 挂载 `/opt/duoqi-api`(同上)
|
||||||
|
> - job 容器需要访问宿主机目录,通过 `config.yaml` 中的 `container.options` 和 `valid_volumes` 配置
|
||||||
|
|
||||||
### 环境隔离策略
|
### 环境隔离策略
|
||||||
|
|
||||||
#### RDS 数据库隔离
|
#### RDS 数据库隔离
|
||||||
@ -472,21 +479,22 @@ LOG_LEVEL=debug
|
|||||||
|
|
||||||
**服务器 compose 文件** `/opt/duoqi-api/docker-compose.yml`:
|
**服务器 compose 文件** `/opt/duoqi-api/docker-compose.yml`:
|
||||||
|
|
||||||
|
> 代码库中对应文件为 `docker-compose.prod.yml`,部署时手动重命名为 `docker-compose.yml`。
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: '3.8'
|
# 使用 host 网络模式,避免 Docker bridge 子网与阿里云 VPC 内网 IP 段冲突
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# ===== 生产环境 =====
|
# ===== 生产环境 =====
|
||||||
api-prod:
|
api-prod:
|
||||||
build:
|
build:
|
||||||
context: /opt/gitea/data/git/repositories/admin/duoqi-api.git
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: duoqi-api:prod
|
image: duoqi-api:prod
|
||||||
container_name: duoqi-api-prod
|
container_name: duoqi-api-prod
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
env_file: .env.prod
|
env_file: .env.prod
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@ -503,17 +511,16 @@ services:
|
|||||||
limits:
|
limits:
|
||||||
memory: 400M
|
memory: 400M
|
||||||
|
|
||||||
# ===== 测试环境(按需启停) =====
|
# ===== 测试环境(Docker profiles 按需启停) =====
|
||||||
api-test:
|
api-test:
|
||||||
build:
|
build:
|
||||||
context: /opt/gitea/data/git/repositories/admin/duoqi-api.git
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: duoqi-api:test
|
image: duoqi-api:test
|
||||||
container_name: duoqi-api-test
|
container_name: duoqi-api-test
|
||||||
restart: "no" # 不自动重启,手动控制
|
restart: "no"
|
||||||
|
network_mode: host
|
||||||
env_file: .env.test
|
env_file: .env.test
|
||||||
ports:
|
|
||||||
- "3001:3001"
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@ -530,7 +537,7 @@ services:
|
|||||||
limits:
|
limits:
|
||||||
memory: 300M
|
memory: 300M
|
||||||
profiles:
|
profiles:
|
||||||
- test # 使用 profiles 按需启停
|
- test
|
||||||
```
|
```
|
||||||
|
|
||||||
**启停命令:**
|
**启停命令:**
|
||||||
@ -621,9 +628,11 @@ git push origin main
|
|||||||
| 生产部署手动确认 | 防止误操作,确保人工验证后才上线 |
|
| 生产部署手动确认 | 防止误操作,确保人工验证后才上线 |
|
||||||
| 使用 Gitea Actions | 兼容 GitHub Actions 语法,学习成本低 |
|
| 使用 Gitea Actions | 兼容 GitHub Actions 语法,学习成本低 |
|
||||||
| Runner 使用 `network: host` | 容器共享宿主机网络,解决容器无法访问 Gitea 的问题 |
|
| 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 使用 `github_mirror` | 从 gitea.com 镜像拉取 Actions,解决国内无法访问 GitHub 的问题 |
|
||||||
| 自定义 Runner 镜像(bun + git + docker CLI) | 避免 checkout REST API 不兼容,支持 CI 中执行 docker 命令 |
|
| 自定义 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 版本变化导致意外失败 |
|
| 固定 Bun 版本(1.3) | 确保 CI 环境可复现,避免 latest 版本变化导致意外失败 |
|
||||||
|
|
||||||
### 部署操作
|
### 部署操作
|
||||||
@ -840,11 +849,10 @@ services:
|
|||||||
# Phase 2: 多实例 docker-compose.yml
|
# Phase 2: 多实例 docker-compose.yml
|
||||||
# API 服务器上的配置
|
# API 服务器上的配置
|
||||||
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
api:
|
api:
|
||||||
image: your-registry/duoqi-api:latest
|
image: your-registry/duoqi-api:latest
|
||||||
|
network_mode: host
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 2 # 运行 2 个实例
|
replicas: 2 # 运行 2 个实例
|
||||||
resources:
|
resources:
|
||||||
@ -1036,6 +1044,48 @@ mysql -h your-rds-endpoint -u duoqi_prod -p -e "SELECT 1;"
|
|||||||
# 阿里云 RDS 控制台 → 数据安全性 → 白名单设置
|
# 阿里云 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 <network-name>
|
||||||
|
|
||||||
|
# 解决方案 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
|
```bash
|
||||||
@ -1113,6 +1163,6 @@ docker compose up -d api-prod
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**文档版本**: v5.2.0 (双分支工作流 + 国内网络适配 + Docker 执行器完善)
|
**文档版本**: v5.3.0 (host 网络模式 + Act Runner 挂载配置 + 故障排查更新)
|
||||||
**最后更新**: 2026-04-17
|
**最后更新**: 2026-04-18
|
||||||
**维护者**: Duoqi Team
|
**维护者**: Duoqi Team
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user