Repository navigation
Conversation
此前发布全靠本地跑 build-and-push.sh 再手动登服务器,仓库没有任何 CI。 新增两个工作流: - ci.yml:PR 校验。后端 mvn compile、前端 pnpm build、nginx -t,不碰服务器。 - deploy.yml:push 到 main 后构建前后端镜像 → 推送阿里云 ACR → SSH 登录轻量 服务器拉取重启 → 健康检查。只改 .md/docs 不触发。 顺带修掉一个一直存在的不一致:build-and-push.sh 里 REPO="acr",推的是 lucas_acr/acr:*,而 docker-compose.yml 拉的是 lucas_acr/rag-agent-platform:*, 两边仓库名对不上。以 compose 为准统一。 镜像同时打 commit SHA 和 latest 两个标签,部署时把 SHA 写进服务器 .env 的 IMAGE_TAG,compose 据此拉取精确版本——线上跑的是哪个 commit 可追溯,回滚只需 改这一行。未设置时回落到 latest,本地和手动流程不受影响。 服务器上的 .env 存着密钥,CI 只做 IMAGE_TAG 的原地替换,不覆盖、不外传。 验证:两个 workflow 的 YAML 可解析;deploy.yml 全部 5 个 run 步骤通过 bash -n; compose 在设置和不设置 IMAGE_TAG 两种情况下均插值正确;.env 改写逻辑在 Linux 容器内验证过幂等性(重复部署不会追加重复行,且保留原有变量)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nginx -t 在配置检查阶段就会解析 proxy_pass 的 upstream 主机名,CI 环境里没有 backend/frontend 容器,解析不到直接 emerg 退出: nginx: [emerg] host not found in upstream "backend" 用 --add-host 造两条 hosts 记录让名字可解析。校验的是配置语法,解析到哪个地址无关紧要。 (此前本地验证通过是假阳性:本地 DNS 对未知域名有应答,没有复现 CI 的干净环境。 本次用 --network none 先复现出同样的报错,再确认修复有效。) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
原方案是 CI 主动 SSH 推进服务器,要求 22 端口对公网可达,且 GitHub Secrets 里 要存服务器私钥。改成自托管 runner 后连接方向反转:runner 主动向 GitHub 轮询任务, 纯出站连接——服务器不开放任何入站端口,Secrets 里也不再有服务器凭据。 Secrets 从 7 个减到 3 个:ACR_USERNAME、ACR_PASSWORD、DEPLOY_PATH。 runner 作为 docker-compose.yml 的一个服务,跟其他容器一起起停,不需要单独安装或 配置 systemd。用 PAT 换取一次性注册令牌,退出时自动注销,不会留下僵尸 runner。 构建仍留在 GitHub 云端 runner——轻量服务器扛不住 Maven 和 Next.js 构建的开销, 自托管 runner 只负责拉取重启,几秒钟的事。 两个实现上的坑,已处理并在注释里写明原因: - 部署命令必须显式限定到 backend/frontend。runner 自己也在 compose 里,裸的 up -d 会把它一起重建,当场杀掉正在执行的部署任务。 - 项目目录必须挂载到与宿主机完全相同的绝对路径。compose 把相对路径解析成绝对路径 后交给宿主机守护进程按宿主机文件系统查找,容器内外路径不一致就会挂载错位置。 - 健康检查用服务名而非 localhost:脚本跑在 runner 容器内,localhost 指向 runner 自己。 安全约束:deploy.yml 只允许 push 到 main 触发。这是公开仓库,一旦 fork 的 PR 能 触发工作流,任何人都能在服务器上执行任意代码。已在工作流和文档中标注。 验证:runner 镜像构建通过,镜像内 docker/compose/jq 与 runner 脚本齐备;entrypoint 在缺少变量、PAT 无效等情况下均给出可读的失败原因(此前 set -e 会让报错在提示打印前 就终止,已修);compose 在 DEPLOY_PATH 变化时挂载源与目标始终一致;deploy.yml 三个 run 步骤通过 bash -n,且确认不含 pull_request 触发器。 端到端未验证——需要真实 PAT 与服务器,首次运行才能确认。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
国内服务器构建 runner 镜像时挂在拉取 docker 官方 apt 源的 GPG key: curl: (35) Recv failure: Connection reset by peer failed to solve: ... exit code: 35 download.docker.com 在国内会被重置。改为多阶段从官方 docker:28-cli 镜像直接拷贝 docker 二进制与 compose 插件——Docker Hub 是通的(同一次构建里 ubuntu:24.04 拉取正常), 彻底不碰那个 apt 源。顺带去掉了只为导入 GPG key 而装的 gnupg。 同时把 ubuntu apt 源换成阿里云镜像:官方源实测只有 352kB/s,光拉软件包列表就要 1 分半。 用 http 而非 https,因为基础镜像里还没有 ca-certificates,https 源会因无法校验证书而失败; apt 包自带 GPG 签名,完整性不依赖 TLS。amd64 与 arm64 的源地址不同,两种都覆盖。 镜像源做成 APT_MIRROR 构建参数,传空字符串即可退回官方源。 runner tarball 下载补了 --retry 5,弱网下更稳。 新增 docs/TROUBLESHOOTING_LOG.md:记录本次线上问题的现象、五个根因、修复方案, CI/CD 架构选型与实现中的三个坑,以及部署过程踩坑实录(含错误原文便于检索)和经验教训。 配图目录待补截图。 验证:镜像构建通过(含换源后的 apt 与 GitHub 上的 runner tarball 下载);镜像内 docker 28.5.2 / compose v2.40.3 / jq / git / runner 脚本齐备;PAT 无效时错误提示正常。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
新增: - 3.6 构建 runner 镜像卡在 download.docker.com(含关键观察:同一次构建里 Docker Hub 是通的,只有该域名不通,这个区分决定了修复方向) - 3.7 apt 官方源太慢换阿里云镜像(含两个易踩细节:Ubuntu 24.04 改用 DEB822 格式导致老教程失效;必须用 http 因为基础镜像尚无 ca-certificates) - 3.8 git pull 报 no tracking information(根源是前一步用 checkout -B FETCH_HEAD 建分支未建立上游关联) 经验教训新增第 8~11 条:网络故障要先缩小到具体域名;国内换源要分清哪些能换 (系统包和语言包可以,可执行二进制不行——拿到 root 级权限,来源可信度不能牺牲); 抄教程前先确认版本,改完要验证结果而非只看命令是否报错;排查报错先回顾前几步 自己做了什么。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
国内直连 github.com 下载 runner tarball 实测约 25 KB/s,215MB 需要 2.5 小时, 不可用。 改为可通过 RUNNER_DOWNLOAD_BASE 指定加速镜像,同时**强制校验 SHA256**(哈希由 GitHub 官方发布,已本地下载实测比对确认)。文件一旦被篡改校验失败、构建中止。 这与"不从不可信来源下载 root 级二进制"的原则并不冲突:反对的是无校验地信任第三方, 有官方哈希兜底则是安全的。校验对默认的官方源同样生效。 APT_MIRROR 与 RUNNER_DOWNLOAD_BASE 都提到 docker-compose.yml 的 build.args, 可直接在 .env 里覆盖,不必每次记 --build-arg。 验证:官方 SHA256 经本地完整下载比对确认一致;compose 构建参数在默认与 .env 覆盖两种情况下均正确传递。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.9 记录 runner tarball(215.5MB)国内直连仅 25 KB/s(预计 2 小时 32 分)的问题、 四个候选源的实测速度对比(最快与最慢差 55 倍)、测速方法,以及"换镜像站 + 强制校验 官方 SHA256"的解法与配置方式。 同时修正第 9 条经验教训:原文写"可执行二进制不要换源",过于绝对。关键区分是 "无校验地信任镜像站"不可接受,而拿到官方哈希并强制校验后使用镜像站是安全的。 没有官方哈希可对照时才回到"宁可慢也不换源"。 runner 已在阿里云服务器注册成功并处于 online 状态。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
仓库此前没有任何 CI(无
.github/目录),发布全靠本地跑build-and-push.sh再手动登服务器。架构:不用 SSH
构建跑在 GitHub 云端 runner,部署跑在服务器上的自托管 runner:
自托管 runner 主动向 GitHub 轮询任务,纯出站连接。因此服务器不需要开放 SSH 或任何入站端口,GitHub Secrets 里也不存放服务器凭据 —— Secrets 从 7 个减到 3 个(
ACR_USERNAME/ACR_PASSWORD/DEPLOY_PATH)。runner 本身就是
docker-compose.yml里的一个服务,跟其他容器一起起停,不需要单独安装或配置 systemd。用 PAT 换取一次性注册令牌,退出时自动注销,不留僵尸 runner。新增
ci.yml—— PR 校验:后端mvn compile、前端pnpm build、nginx -t,不碰服务器deploy.yml—— push main 后:构建推 ACR → 自托管 runner 拉取重启 → 健康检查deploy/runner/—— runner 镜像与启动脚本三个实现上的坑(已处理,注释里写明原因)
up -d会把它一起重建,当场杀掉正在执行的部署任务。localhost指向 runner 自己。顺带修掉的不一致
build-and-push.sh里REPO="acr",推的是lucas_acr/acr:*;而docker-compose.yml拉的是lucas_acr/rag-agent-platform:*—— 两边仓库名对不上。以 compose 为准统一。版本可追溯 / 回滚
镜像同时打
<sha>和latest。部署时把 commit SHA 写进服务器.env的IMAGE_TAG,所以「线上跑的是哪个 commit」随时可查,回滚只需改这一行再up -d。未设置时回落latest,手动流程不受影响。deploy.yml只允许push到 main 触发,绝不能加pull_request。这是公开仓库 —— 一旦 fork 的 PR 能触发工作流,任何人都能在服务器上执行任意代码。已在工作流注释和 DEPLOY.md 中标注。另:CI 只对服务器
.env做IMAGE_TAG一行的原地替换,不覆盖、不读取、不外传。验证
set -e会让报错在提示打印前就终止,已修)DEPLOY_PATH变化时挂载源与目标始终一致deploy.yml三个 run 步骤通过bash -n,确认不含pull_request触发器nginx -t用--network none复现出 CI 的失败条件后再验证修复🤖 Generated with Claude Code