先拆小命令定位

把命令拆小,不直接跑整条 CI。

场景命令位置第一刀
本地登录慢Mac 终端查 DNS、TLS、Docker Desktop
Actions 登录失败workflow查 permissions 和 token
push 卡住CI 发布镜像查镜像层和缓存
服务器 pull 失败部署机查 read 权限和出口

如果日志停在 Login Succeeded 之后,那就不是登录超时,而是 push 或 pull 慢。这个区分能省很多无效换 token 的时间。

处理步骤

先在本地用最小命令验证:docker login ghcr.io -u USERNAME,密码用 PAT。确认是超时、401、403,还是 TLS 报错。超时看网络和 DNS;401/403 看权限。

再检查 PAT 或 GITHUB_TOKEN。PAT 至少要和你的动作匹配:读私有包需要读权限,发布需要写权限。GitHub Actions 里别默认权限,显式写:packages: write 和必要的 contents: read

接着区分 registry 地址。GitHub Container Registry 是 ghcr.io,不要和旧的 Docker package endpoint 混用。镜像名也要带 owner,例如 ghcr.io/org/app:tag

最后看 CI runner。自托管 runner、公司网络、远程办公室和云厂商出口都可能对 registry 连接不稳定。GitHub-hosted runner 通常少一些环境差异,但也要看依赖缓存和镜像层大小。

CI 里怎么写更稳?

项目建议
登录docker/login-action 或明确 docker login
Token同仓库优先 GITHUB_TOKEN
权限workflow 顶部声明 packages: write
镜像名固定 ghcr.io/<owner>/<name>
tag同时写 sha 和 semver
超时不在失败时无限重试

我还会把 build 和 push 分开打日志。很多 workflow 一行里做完 login、build、push,失败时只剩一个红叉。拆开后,你才知道是 registry 登录、构建缓存,还是上传镜像层的问题。

远程团队为什么更容易遇到

独立开发者常见的环境是:本地在一个地区,CI 在 GitHub,部署在另一家云,队友又在旅行。任何一段连 ghcr.io 慢,都会被误判成 GitHub Packages 坏了。实际上更常见的是 DNS、TLS、凭据过期、组织权限和镜像可见性。

另一个坑是权限继承。私有仓库生成的包,不一定自动对所有部署环境可读。组织迁移、仓库改名、包从 private 改 internal,都可能让旧部署 token 失效。

GitHub Container Registry login 继续排查清单

  • GITHUB_TOKEN 是否有 packages: write
  • PAT 是否过期,是否只有读权限却在 push
  • 镜像是否发布到正确 owner
  • package 是否关联到仓库
  • 部署平台是否能访问 ghcr.io
  • 自托管 runner 的 Docker credential helper 是否损坏
  • 是否把 push 慢误判成 login 慢

我还会检查 .docker/config.json。本地换过 Docker Desktop、credential helper 或登录多个 registry 后,这个文件里可能留着旧凭据。CI 里则要避免把本地配置复制进镜像构建上下文。凭据问题有时不是没有权限,而是拿错了旧权限。

另一个容易忽略的是镜像标签。latest 方便,但排查很痛苦。生产部署最好同时使用 git sha tag,失败时能回到确定版本。否则你以为是登录超时,实际上是部署机拉到了刚被覆盖的新镜像,行为和日志都对不上。

如果团队里有人在本地手动 push 镜像,我会尽快收口到 CI。手动 push 的问题不是技术上不能用,而是没有审计线索。CI 至少能留下 commit、runner、token、镜像 digest 和失败日志。等到生产拉取失败时,这些信息比任何口头描述都可靠。

最后看一次 registry 配额和并发。小团队常把前端、worker、后台任务都塞进同一个镜像发布流程,一次合并触发多条 push。并发多了以后,日志里看着像登录慢,实际是上传层排队。把无关服务拆成独立 workflow,失败面会小很多,也更容易回滚即可。

还没恢复时的排查

把镜像发布改到 GitHub-hosted runner 跑一遍,排除自托管 runner 环境问题;再把部署拉取改成只读 token。远程团队如果经常处理 GitHub Actions、Cloudflare、容器 registry 后台,可以准备海外服务跑 GitHub Actions / Cloudflare 的稳定线路,至少让排查环境固定下来。

相关阅读