tunnel-system:从本地开发到 CI/CD + Docker + 模型权重 的完整流程

基于当前仓库实际配置整理(校对时间:2026-03-01)。 适合准备发博客、希望“一篇讲清楚”的读者。


0. 一句话总览

git push main 之后:

  1. GitHub Actions 在云端构建前后端镜像;
  2. 镜像推送到 GHCR(GitHub Container Registry);
  3. Actions 通过 SSH 登录服务器,执行 docker compose -f docker-compose.prod.yml pull && up -d
  4. 容器运行时通过 volume 挂载读取服务器本地模型权重(权重不在镜像里)。

1. 先建立正确心智模型(最重要)

  • CI(持续集成):自动构建镜像(必要时可加测试)。
  • CD(持续部署):把新镜像自动部署到服务器。
  • Dockerfile:镜像“制造说明书”(主要在 CI 阶段使用)。
  • docker-compose.prod.yml:生产“运行说明书”(主要在服务器部署时使用)。
  • 核心边界:CI/CD 负责镜像与部署流程,不会自动上传你本地模型文件。

2. 项目里哪些文件分别负责什么

2.1 自动化总导演

  • .github/workflows/deploy.yml
  • 触发条件:pushmain
  • 工作流分为两个 job:builddeploy

2.2 镜像构建

  • backend/Dockerfile:构建后端运行镜像(Go API + Python ML 运行环境 + third_party/sam2
  • frontend/Dockerfile:先用 Node 构建前端,再用 Nginx 承载静态产物

2.3 生产运行编排

  • docker-compose.prod.yml
  • 使用 image:(拉远端镜像),不是 build:(服务器不本地构建)
  • 默认端口映射:前端 8080:80,后端 8000:8000

2.4 本地 Docker 编排

  • docker-compose.yml
  • 使用 build:,适合本地 docker compose up --build

2.5 本地一键开发脚本

  • scripts/run_dev.sh
  • 做环境准备并启动前后端开发服务,不等同于生产部署

3. CI/CD 实际执行细节(按真实流程)

3.1 Build 阶段(GitHub Runner)

deploy.yml 中,Actions 会:

  1. checkout 代码;
  2. 登录 GHCR;
  3. 构建并推送后端镜像:
    • ghcr.io/xwrock-ce/tunnel-system-backend:main
    • ghcr.io/xwrock-ce/tunnel-system-backend:<commit-sha>
  4. 构建并推送前端镜像:
    • ghcr.io/xwrock-ce/tunnel-system-frontend:main
    • ghcr.io/xwrock-ce/tunnel-system-frontend:<commit-sha>

结论:同一次提交会产出 mainsha 两种标签,sha 可追溯、可回滚。

3.2 Deploy 阶段(远程服务器)

deploy.ymlappleboy/ssh-action 登录服务器后,会做:

  1. 进入部署目录:/srv/tunnel-system
  2. 若目录已是 git 仓库,则 fetch + reset 到目标分支;否则按条件初始化仓库;
  3. 确保 .env 存在(必要时从 .env.example 复制);
  4. 把 GitHub Secrets 中的 ADMIN_USERNAME / ADMIN_PASSWORD 写入或更新到 .env
  5. 创建运行目录:model_weightsuploadsstatic
  6. 登录 GHCR(使用 GHCR_PAT);
  7. 执行 Docker 清理,降低磁盘打满风险;
  8. 用当前提交 SHA 部署:
    • IMAGE_TAG=$GITHUB_SHA docker compose -f docker-compose.prod.yml pull
    • IMAGE_TAG=$GITHUB_SHA docker compose -f docker-compose.prod.yml up -d --remove-orphans

结论:服务器“会自动拉镜像并重启”是因为 Actions 在远程执行了这些命令。


4. Docker 与模型权重:为什么必须分开

4.1 为什么权重不进镜像

  • 体积大、更新频率与代码不同;
  • 便于权限与资产管理;
  • 避免每次改权重都重建并分发超大镜像。

4.2 真实挂载关系

docker-compose.prod.yml 中:

  • ./model_weights:/app/model_weights:ro
  • ./uploads:/app/uploads
  • ./static:/app/static

意味着:

  • 服务器 /srv/tunnel-system/model_weights → 容器 /app/model_weights

并通过环境变量协同:

  • MODEL_WEIGHTS_DIR=/app/model_weights
  • BASE_DIR=/app
  • SAM2_REPO_PATH=/app/backend/third_party/sam2

4.3 关键坑:不要把本地 symlink 传到服务器

如果你在服务器上放的是“指向你个人电脑路径”的符号链接,容器内会报找不到权重。

✅ 正确做法:服务器目录里放真实权重文件(或在服务器内有效的链接目标)。


5. 本地开发:run_dev.sh 到底做了什么

执行 ./scripts/run_dev.sh 后,脚本会(摘要):

  1. 检查代理环境并在必要时临时取消不可达本地代理;
  2. 检测后端端口(默认 8000,被占用会自动递增);
  3. 检查模型权重是否存在(缺失仅告警,不强制退出);
  4. 准备 backend/.venv(优先 Python 3.12,若检测到 3.13 会提示重建);
  5. 安装/校验 Python ML 依赖;
  6. go mod download 准备 Go 依赖;
  7. 若缺少前端依赖则执行 npm install
  8. 启动后端 go run ./cmd/server 与前端 npm run dev
  9. Ctrl+C 时自动结束两个进程。

注意:run_dev.sh 是开发启动脚本,不会替代 CI/CD 生产部署。


6. 为什么仍建议做 build + test

6.1 前端 build

  • 命令:cd frontend && npm run build
  • 实际执行:tsc -b && vite build
  • 作用:提前发现类型问题、打包问题,避免线上白屏。

6.2 后端测试

  • 命令:cd backend && go test ./...
  • 作用:回归检查鉴权、接口、服务逻辑,降低发布风险。

6.3 Python 测试(可选但推荐)

  • 命令:cd backend && uv run pytest tests -q

7. 管理员账号行为(避免旧认知误导)

当前后端启动时会确保“配置中的管理员账号”可用:

  • 若该用户名不存在:创建;
  • 若存在但密码不一致:会更新为配置密码并激活;
  • 旧的历史默认账号(admin/admin123)在满足条件时会被自动停用。

建议:生产环境务必修改默认 ADMIN_USERNAME / ADMIN_PASSWORDSECRET_KEY


8. 部署后最小自检清单

在服务器执行:

cd /srv/tunnel-system

1. 1) 看容器状态
docker compose -f docker-compose.prod.yml ps

1. 2) 看后端日志(重点看权重与启动)
docker compose -f docker-compose.prod.yml logs --tail=200 backend

1. 3) 看权重文件是否真实存在
ls -lh /srv/tunnel-system/model_weights

1. 4) 看容器内是否可见
docker compose -f docker-compose.prod.yml exec backend ls -lh /app/model_weights

1. 5) 验证登录接口
curl -X POST http://127.0.0.1:8000/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"你的管理员账号","password":"你的管理员密码"}'

9. 常见故障速查

  • manifest unknown:镜像标签不存在,先看 Actions 的 build/push 是否成功。
  • 拉镜像失败:检查服务器 docker login ghcr.io 权限(GHCR_PAT)。
  • 登录失败:检查服务器 .env 与数据库中的账号同步情况。
  • 权重找不到:检查文件名、挂载路径、是否是无效 symlink。
  • 端口冲突:生产前端默认占 8080,后端占 8000,冲突时调整映射。

10. 最终结论(可直接放文末)

tunnel-system 的上线并不是“服务器上手工编译代码”,而是“GitHub 构建镜像 + 服务器拉镜像运行”。 模型权重是独立资产,必须在服务器本地可用并通过 volume 挂载给容器。把这两条边界理清,CI/CD、Docker、模型推理链路就不会再混淆。

发表回复

Your email address will not be published. Required fields are marked *.

*
*