跳到主要内容

环境变量:声明、导入、导出

流水线里要拿分支名、要传镜像地址、要注入密码,全靠环境变量。这套东西分四种用法,记住就行。

一、平台已经给了一堆​

最常见的一批,直接 ${变量} 就能用:

.cnb.yml
main:
push:
- stages:
- name: print-vars
script: |
echo "branch: ${CNB_BRANCH}"
echo "commit: ${CNB_COMMIT_SHORT}"
echo "repo: ${CNB_REPO_SLUG}"
echo "build id: ${CNB_BUILD_ID}"
echo "event: ${CNB_EVENT}"
echo "event url: ${CNB_EVENT_URL}"

分类记一下,用的时候知道去哪找:

类别代表变量
品牌标识CI、CNB(值都是 true)
Web / API 地址CNB_WEB_HOST、CNB_WEB_ENDPOINT、CNB_API_ENDPOINT
组织与仓库CNB_GROUP_SLUG、CNB_ROOT_SLUG、CNB_REPO_SLUG、CNB_REPO_SLUG_LOWERCASE
分支与事件CNB_BRANCH、CNB_BRANCH_SHA、CNB_DEFAULT_BRANCH、CNB_EVENT
提交CNB_COMMIT、CNB_COMMIT_SHORT、CNB_COMMIT_MESSAGE_TITLE、CNB_BEFORE_SHA
构建CNB_BUILD_ID、CNB_BUILD_USER、CNB_IS_CRONEVENT
令牌与制品CNB_TOKEN、CNB_TOKEN_USER_NAME、CNB_DOCKER_REGISTRY、CNB_HELM_REGISTRY

注意两点:

  • 这些都是只读的,你在流水线里覆盖不掉
  • CNB_BRANCH 在 PR 事件里取的是目标分支名;CNB_EVENT_URL 在 PR/Issue 事件里是 PR/Issue 的链接,在 push 里是 commit 链接

CNB_REPO_SLUG_LOWERCASE 特别常用——镜像名必须小写,组织名带大写时就得靠它。

二、自己声明​

.cnb.yml
main:
push:
- docker:
image: node:22
env:
REGISTRY: registry.example.com
PIPELINE_FLAG: pipeline-level
stages:
- name: 用 pipeline 级变量
script: echo $PIPELINE_FLAG
- name: 用 stage 级变量
env:
ONLY_HERE: stage-level
script: echo $ONLY_HERE
  • 写在 pipeline 上 → 整条流水线都能用
  • 写在 stage 上 → 只对这一条任务有效

三、从密钥仓库导入​

密码、Token 不该出现在 .cnb.yml 里。做法是放进密钥仓库的一个 yml 文件,然后 imports 它:

密钥仓库中的 env.prod.yml
DOCKER_USER: "prod_username"
DOCKER_TOKEN: "prod_token_123456"
DOCKER_REGISTRY: "registry.prod.com"
.cnb.yml
main:
push:
- services:
- docker
imports:
- https://cnb.cool/<组织>/<密钥仓库>/-/blob/main/env.prod.yml
stages:
- name: 构建并推送镜像
script: |
docker login -u $DOCKER_USER -p "$DOCKER_TOKEN" $DOCKER_REGISTRY
docker build -t $DOCKER_REGISTRY/$CNB_REPO_SLUG_LOWERCASE:latest .
docker push $DOCKER_REGISTRY/$CNB_REPO_SLUG_LOWERCASE:latest

三条必须知道的规则:

  1. env 和 imports 冲突时,env 优先
  2. 默认只有密钥仓库的管理员 / 负责人触发的流水线才能引用
  3. 想让更多人能用,得在密钥文件里声明 allow_slugs、allow_events、allow_branches、allow_images——一旦配了 allow_*,系统就忽略触发者角色,完全按规则校验

四、把一个任务的输出传给下一个任务​

exports 就是把某个任务的 result 映射成环境变量,生命周期是整条 pipeline:

.cnb.yml
main:
push:
- stages:
- name: 生成版本号
script: echo "v1.2.3"
exports:
stdout: VERSION
- name: 用版本号
script: echo "版本是 $VERSION"

script 任务的 result 有四个属性可用:code、stdout、stderr、info。

想做精细处理时用 printf 去掉末尾换行:

- name: 生成
script: printf "%s" "v1.2.3"
exports:
stdout: VERSION

内置任务的 result 是结构化对象,可以深层取值(类似 lodash.get):

- name: 随机加评审人
type: git:reviewer
options:
type: add-reviewer-from-repo-members
exports:
reviewersForAt: REVIEWERS_FOR_AT
- name: 通知
script: 'echo "please review: $REVIEWERS_FOR_AT"'

五、常见坑​

现象原因
$VERSION 是空的exports 只在同一条 pipeline 内有效,跨 pipeline 不传
docker login 失败但变量看着有值$DOCKER_TOKEN 里有特殊字符,要加引号
引用了另一个仓库的 env 文件报无权限不在 allow_* 白名单内,或触发者是不可信事件
覆盖内置变量没生效内置变量只读