```html 每个工程师都熟悉那个瞬间:卡了很久的 bug 终于修完,代码推上去,人坐在屏幕前等那个绿色的勾。

打开网易新闻 查看精彩图片

我也等过。那还是实习期,Terraform 一直因为磁盘错误创建不了数据库服务器。在一位资深工程师的帮助下,我找到了原因:AMI 过滤器抓错了镜像,那个镜像需要的磁盘比我申请的大。我改掉过滤器,推了改动,然后开始等。

流水线没有变绿。它也没有真正变红——它压根没跑。

有时候流水线坏了,而你的代码完全没问题。下面是发生了什么、怎么修好的,以及我会怎么做来避免它再次打你个措手不及。

五个失败任务,零条日志

流水线页面把整件事标成了失败:5 个任务,全部是红的。

正常情况下这没什么。点进一个任务,打开日志,滚到红字那里,找到自己的错误。

这次没东西可读。失败原因只写了一句话:No more compute minutes available(没有可用的计算分钟了)。

没有任务日志,没有堆栈跟踪,没有 Terraform 报错,什么都没有。这些任务根本没启动,所以也没有任何东西可记录。

如果你哪天看到一个满是失败任务、却一条日志都没有的流水线,先查这个。

重试让它看起来更糟

我当然点了重试。谁不点呢。结果它没有运行,GitLab 在页面顶部甩出这么一句:

An error occurred while making the request. Status cannot transition via "drop"

这句话看着相当吓人,像是 GitLab 内部有什么东西坏了。据我判断,它只是 GitLab 在更新那些根本没机会启动的任务时失败了。同一个问题,换了个更让人困惑的说法。

分钟数没回来之前,重试不会有用,你只会一遍遍收到同样的报错。等分钟数充值之后,一次重试就够了。

计算分钟属于账户,不属于你

这是当实习生时没人告诉你的部分:这个问题你大概率自己修不了。

我把情况告诉了审核我改动的资深工程师。她也查不了月度配额,于是把我指给了管理我们 GitLab 账户的同事。后来我才知道原因:查看一个组的用量需要 Owner 角色,所以很多开发者连自己离上限还有多远都看不到。

所以翻自己的代码没有意义。修复方式是给对的人发一条消息。我大致是这么写的:

“你好,我们 Terraform 项目的 GitLab 流水线停止运行了,提示本月的 CI 计算分钟已经用完。方便的时候能帮忙查一下配额吗?我有个改动已经准备好了,只是没有计算资源就跑不起来。”

他确认我们已经用完,并给账户充了值。

烦人的是时间点。等审核加上这一出,我的工单好几天几乎没动,站会上还得解释:活已经干完了,但什么都跑不了。如果你也遇到这种情况,说简单点就行——什么做完了、卡在哪、谁在处理。

怎么提前查

如果你是组上的 Owner,进入这个组(不是子组),然后点 Settings > Usage quotas。个人账户则在左侧边栏的 Usage quotas 里看。

有几件事我希望自己早点知道:

- 用量每月重置,所以这个问题通常在月底前后咬人。 - GitLab 在 16.1 版本把“CI/CD minutes”改名为“compute minutes”,所以旧的 Stack Overflow 回答用的还是老名字。 - 如果你不是 Owner,请 Owner 帮忙盯着。这比我这样干到一半才发现要省事得多。

怎么让分钟数更耐用

如果我想让这事不再发生,会从这几处下手。

只在相关文件变化时运行任务。如果你的 Terraform 拆成了多个组件,只动了负载均衡就没必要去 plan 数据库,用 rules: changes: 就能解决:

plan:db: script: - terraform -chdir=db plan rules: - changes: - db/**/*

停掉重复流水线。往一个已有合并请求的分支推代码,可能同时启动两条流水线,一条给分支,一条给合并请求。在 .gitlab-ci.yml 顶部加一段 workflow: rules 可以保证只跑一条。

再次推送时取消旧流水线。五分钟里推了三个修复?你不需要三条流水线都跑完。把任务标记为 interruptible: true,并在 CI/CD 设置里打开冗余流水线自动取消。

缓存每次都要下载的东西。依赖和 Terraform provider 默认每次运行都会重新下载,除非你做了缓存。

把昂贵的任务改成手动。如果某个任务不需要每次推送都跑,when: manual 就是你要的。

重活用自己的 runner。按 GitLab 文档的说法,项目和组的 runner 不受计算配额影响。如果团队已经有服务器,自管理的 runner 可以把重活完全从配额里挪走。

最后

有意思的是,我的修复从头到尾都是对的。流水线只是没有东西可跑。

所以我也好奇:你遇到过最离谱的、跟代码毫无关系的流水线失败原因是什么?