环境变量:声明、导入、导出
流水线里要拿分支名、要传镜像地址、要注入密码,全靠环境变量。这套东西分四种用法,记住就行。
一、平台已经给了一堆
最常见的一批,直接 ${变量} 就能用:
.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
三条必须知道的规则:
env和imports冲突时,env优先- 默认只有密钥仓库的管理员 / 负责人触发的流水线才能引用
- 想让更多人能用,得在密钥文件里声明
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_* 白名单内,或触发者是不可信事件 |
| 覆盖内置变量没生效 | 内置变量只读 |