2915 字约 10 分钟
问题反馈前,建议先查看对应文档,在下面常见问题和 feedback(在新窗口打开) 中查看问题是否已经存在。
若未能找到答案,请于 feedback(在新窗口打开) 中提交 issue。
触发与配置
流水线为什么没触发?
要定位流水线没触发问题,先要了解流水线从触发到执行的流程。
以 push 事件为例:
其中
skip 检测包括ifNewBranch、ifModify,参考语法。
那么可以按照这个流程一层层查下去:
- 代码是否 push 到远端?
- 对应分支是否有
.cnb.yml?- include 的文件是否有权限
- 配置内容无格式、语法问题
.cnb.yml是否声明了当前分支的push事件流水线?- 是否命中了 skip 检测?
CNB 中默认分支通常为
main,一些迁移自其他平台的仓库可能默认分支为master,请注意区分。
在一个分支配置了另一个分支的流水线,为什么没生效?
.cnb.yml 中的流水线配置只对当前分支生效。在 A 分支下配置 B 分支的流水线,并不会使 B 分支的事件按此配置执行。实际执行取决于各分支自身 .cnb.yml 文件的配置。
例如,在 main 分支的 .cnb.yml 中写了 dev 的 push 配置,当 dev 分支 push 时,系统会读取 dev 分支自己的 .cnb.yml,而不是 main 分支的。
详细说明参考 触发分支。
Fork 仓库为什么不自动触发流水线?
出于安全考虑,Fork 后的仓库默认不会自动触发流水线(包括 Git 操作事件、定时任务事件、Issue 事件)。
如需启用,可在源仓库页面依次进入 设置 → 云原生构建,勾选「Fork 的仓库默认允许自动触发」。
注意:即使启用了自动触发,Fork 仓库流水线中的
CNB_TOKEN权限也会被限制在当前仓库范围内。
详细说明参考 Fork 仓库触发限制。
如何跳过流水线执行?
在 push、commit.add 和 branch.create 事件中,以下两种方式可以跳过流水线:
- 在 commit message 中添加
[ci skip]或[skip ci]:
git commit -m "docs: update readme [ci skip]"
git push origin main- 使用 git push 选项:
git push origin main -o ci.skip详细说明参考 跳过流水线。
为什么插件任务拿不到 env / imports 设置的环境变量?
这是脚本任务和插件任务的核心区别之一。插件任务不会接收通过 env 或 imports 声明的自定义环境变量,只能使用 CNB 内置的系统环境变量。
插件任务的参数应通过 settings 传递:
# ❌ 错误:env 声明的变量不会传递给插件
- name: wrong
image: plugins/npm
env:
PLUGIN_USERNAME: $NPM_USER
# ✅ 正确:通过 settings 传递参数
- name: correct
image: plugins/npm
settings:
username: $NPM_USER详细对比参考 脚本任务 vs 插件任务。
执行与调试
在本地明明好的,为什么在 CI 上跑失败了?
要定位这个问题,首先要明确本地环境和 CI 环境的区别:
| 本地 | CI 环境 | |
|---|---|---|
| 网络 | 本地网络(比如一些办公内网) | CI 机器所在网络 |
| 文件 | 本地整个目录下所有文件 | Git 仓库对应分支代码 |
| 环境 | 原生 | 指定的 Docker 容器环境 |
| Shell | 本地指定 | sh |
了解到差异,我们可以依次排查:
- 是否有文件未提交?
- 构建依赖的文件是否命中
.gitignore? - 是否依赖本地才有的资源(如本地接口、凭证等)?
- CI 声明的 cpus 是否满足要求?
- 本地运行相同的镜像,得到与 CI 相同的构建环境,进行调试。
云原生构建 的默认镜像为 cnbcool/default-build-env(在新窗口打开)。
那么,我们可以执行下面命令,进入默认 CI 环境进行调试:
docker run --rm -it -v $(pwd):$(pwd) -w $(pwd) cnbcool/default-build-env sh如果声明了其他镜像作为流水线构建环境,请将上述命令中 cnbcool/default-build-env 替换成对应镜像地址。
如何登录到流水线容器调试?
参考 登录调试。
流水线执行脚本和登录调试执行脚本结果不一样?
流水线默认使用 sh,登录调试使用的是 bash,两者语法存在差异。
如果确认流水线容器支持 bash(默认容器支持,自定义容器可能不支持),可以将执行脚本改为:
bash xxx.sh
# 或
bash -c '原来的语句'流水线超时无输出?
一个 job 如果超过 10 分钟没有日志输出,就会被终止。可以考虑增加日志输出,例如针对 npm install 的情况,可以加上 --verbose 参数。
注意这个跟 job 的 timeout 声明的超时不一样,不能通过配置修改。
为什么 PR 流水线中 docker push / git push 失败?
PR 相关事件属于不可信事件,流水线中的 CNB_TOKEN 权限会被限制——代码和制品库仅有只读权限,因此 docker push、git push 等写操作会失败。
这是出于安全考虑:PR 的源分支代码可能被未授权用户修改,若赋予写权限,可能导致恶意代码注入或构建产物被篡改。
解决方案:将涉及推送的任务放到 push、pull_request.target 或 tag_push 等可信事件中执行。
没改代码为什么流水线就失败了?
可以检查依赖的其他资源是否有变动,比如:
- 插件任务声明镜像版本为
latest,镜像是否有变动。 - CI 配置文件引用了其他仓库文件,被引用文件是否有变动。
- 有可能网络波动,Rebuild 试试。
如何查看流水线完整日志?
CI 服务发送插件任务和脚本任务至 Runner 执行。如果任务日志过长,将会被截断并返回给 CI 服务。
阶段会汇总其下所有任务的日志。若阶段日志过长,也会被截断以便更好地展示在日志页面上。
构建完成后,您可在日志页面流水线右上角点击日志下载按钮查看完整日志。
缓存与环境
为什么缓存(volumes)有时不生效?
流水线的文件缓存(volumes)是节点级别的,缓存存储在构建节点本地磁盘上。默认情况下,每个仓库的流水线会分配到固定的 3 个节点上执行,因此:
- 跨节点不共享:上次构建在节点 A 写入的缓存,这次如果分配到节点 B,则无法命中。
- 节点可能变化:随着平台扩缩容,分配的节点可能发生变化,旧节点上的缓存不会自动迁移。
如需每次构建都能使用同一份缓存,可以使用 docker:cache 内置任务将缓存构建为 Docker 镜像,实现跨节点缓存。
详细说明参考 流水线缓存。
为什么不提供固定的出口 IP?
CNB 的出口 IP 地址是动态的,可能会随时间变化。
这是因为:
- 运维弹性:平台会根据负载自动扩缩容、迁移节点等运维操作,出口 IP 随之动态变化。
- 安全建议:不建议对 CNB 出口 IP 加白名单。CNB 是公开开放的平台,对出口 IP 加白等同于对公网加白,存在安全风险。
替代方案(如需固定 IP 访问内部服务):
- 私有代理:配置自有代理服务器,通过代理路由请求,使用代理的固定 IP。
- 跳板机:通过 SSH 跳板机连接目标机器执行命令。可使用 cnbcool/ssh 插件。参考示例
- 腾讯云插件:推荐 tencentcom/tcloud-cmd 插件,可远程执行命令,无需白名单配置。
如何构建多架构/多平台镜像?
若需要使用 buildx 构建多种架构/平台的镜像,可以开启 rootlessBuildkitd 特性。需要在服务中声明:
main:
push:
- docker:
image: golang:1.24
services:
- name: docker
options:
rootlessBuildkitd:
enabled: true
env:
IMAGE_TAG: ${CNB_DOCKER_REGISTRY}/${CNB_REPO_SLUG_LOWERCASE}:latest
stages:
- name: go build
script: ./build.sh
- name: docker login
script: docker login -u ${CNB_TOKEN_USER_NAME} -p "${CNB_TOKEN}" ${CNB_DOCKER_REGISTRY}
- name: docker build and push
script: docker buildx build -t ${IMAGE_TAG} --platform linux/amd64,linux/amd64/v2,linux/amd64/v3,linux/arm64,linux/riscv64,linux/ppc64le,linux/s390x,linux/386,linux/mips64le,linux/mips64,linux/loong64,linux/arm/v7,linux/arm/v6 --push .流水线中运行 Docker 镜像时报错 UID/GID 超过 65535?
如果在流水线中遇到类似以下错误:
docker: failed to extract layer ... failed to Lchown ... for UID 100000, GID 100000: lchown ...: invalid argument
(Hint: try increasing the number of subordinate IDs in /etc/subuid and /etc/subgid)原因:
CNB 上的 Docker 采用了 uidmap 技术,会将容器内的 UID 范围限制在 0-65535。当使用的镜像中存在 UID/GID 超过 65535 的文件时,Docker 无法正确映射这些高位 UID/GID,从而导致镜像层解压失败。
解决方案:
重新制作镜像,将这类文件清理掉或者改成正常 UID/GID,不要使用超过 65535 的 UID/GID 的基础镜像来规避此问题。
为什么流水线的仓库存储用量跟页面上显示不一致?
一般来说,流水线上看到的仓库大小应该是跟页面上显示接近的。
但对于所有公开的 Fork 仓库,为了加速构建流程和优化存储空间,目前所有的 Fork 仓库在构建节点上都会复用其祖先仓库的 .git 目录,然后再通过 OverlayFS 技术裂变出多份副本供不同仓库使用。因此在流水线上看到的仓库大小,实际上是包含祖先仓库和所有子孙仓库的仓库大小。
另外,对于普通的仓库,在页面上触发仓库 GC 之后,流水线上仓库大小也不会立马变化,需要等待构建机本身的缓存 GC 逻辑运行后,才会跟页面上显示一致。
代码仓库相关
如何解决代码合并冲突?
若创建 PR 或在 PR 相关事件的构建中碰到代码冲突问题,可以通过如下命令解决:
git fetch origin # 从远端仓库获取更新
git rebase -i origin/main # 实际的目标分支名
# 本地处理冲突
git commit # 根据实际情况提交代码到本地仓库
git push -f # 推送到远端仓库如何彻底删除 Git 仓库里的文件,释放空间?
由于 Git 仓库支持恢复任意历史提交,因此 .git 目录会存储历史上提交的所有文件。单纯删除工作目录中的文件,并不会释放空间。
要彻底删除 Git 仓库里的文件并释放空间,建议通过以下两种方法:
方法一(操作最简单):直接在远端建一个新的仓库,然后把需要的文件复制过去,再改名为原来的仓库。
方法二(操作复杂):通过 git filter-branch 命令或其他第三方工具(如 BFG Repo-Cleaner)在本地彻底删除对应文件后,再强制推送到远程,然后触发远程仓库 GC 流程。