2891 字约 10 分钟
云原生构建 支持声明构建环境和定义构建过程中使用的环境变量。
云原生构建 内置了一些默认环境变量,方便直接使用。
功能概览
环境变量支持以下功能:
| 功能 | 说明 |
|---|---|
| 声明环境变量 | 通过 env 声明环境变量 |
| 导入环境变量 | 通过 imports 导入密钥仓库文件 |
| 导出环境变量 | 将任务结果导出为环境变量 |
| 使用环境变量 | 在脚本和配置中引用环境变量 |
声明环境变量
通过 env 声明环境变量:
- 在
Pipeline中声明的环境变量对整个流水线有效。 - 在
Job中声明的环境变量仅对当前任务有效。
以下示例中,docker.image 声明了构建环境为 node:22, Pipeline 级别的 env 声明了两个流水线环境变量, Job 级别声明了一个仅对当前任务有效的环境变量:
main:
push:
- docker:
image: node:22
env:
PIPELINE_ENV_1: pipeline environment variable 1
PIPELINE_ENV_2: pipeline environment variable 2
stages:
- name: 输出构建环境信息
script: node -v
- name: 输出流水线环境变量
script:
- echo $PIPELINE_ENV_1
- echo $PIPELINE_ENV_2
- name: 输出任务环境变量
env:
JOB_ENV: job environment variable
script: echo $JOB_ENV导入环境变量
通过 imports 导入密钥仓库文件,将敏感信息注入为环境变量,供后续任务使用。
优先级规则
当 env 和 imports 的 key 冲突时,优先使用 env。
示例
以下示例导入密钥仓库文件 envs.yml, 其中的 TEST_DOCKER_DOMAIN、TEST_DOCKER_USER、TEST_DOCKER_PWD 变量可供后续任务使用:
main:
push:
- services:
- docker
imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/envs.yml
stages:
- name: docker info
script: docker info
- name: docker login
script: docker login $TEST_DOCKER_DOMAIN -u $TEST_DOCKER_USER -p $TEST_DOCKER_PWDenvs.yml 内容示例:
# docker 镜像源域名
TEST_DOCKER_DOMAIN: registry.example.com
# docker 用户名
TEST_DOCKER_USER: your_docker_username
# docker 密码
TEST_DOCKER_PWD: your_docker_password导出环境变量
Job 执行结束后,会有 result 对象, 可通过 exports 将其属性导出为环境变量, 生命周期为当前 Pipeline。
语法格式
exports:
from-key: to-key参数说明:
| 参数 | 说明 |
|---|---|
| from-key | Job result 中要导出的属性名 |
| to-key | 映射到环境变量中的变量名 |
from-key支持环境变量,支持深层取值(参考lodash.get)。
result 设置方式
以下三种方式可设置 result:
| 方式 | 说明 |
|---|---|
| 脚本任务执行结果 | 脚本执行完成后的输出 |
| 解析输出中的自定义变量 | 通过特殊格式输出变量 |
| 内置任务的 result | 内置任务返回的结果对象 |
脚本任务执行结果
script 脚本任务执行完成后,Job result 包含以下属性:
| 属性 | 说明 |
|---|---|
| code | 返回码 |
| stdout | 标准输出 |
| stderr | 标准错误 |
| info | stdout 和 stderr 按时序混合 |
输出技巧
可使用 printf "%s" "hello\nworld" 来输出变量,以消除标准输出流最后的换行符, 同时保留 \n 等转义字符。
示例:
main:
push:
- stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
code: CUSTOM_ENV_DATE_CODE
info: CUSTOM_ENV_DATE_INFO
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFO包含判断逻辑时的属性:
当包含 if、ifModify、ifNewBranch 等条件判断时,可额外获取以下属性:
| 属性 | 说明 |
|---|---|
| skip | 任务被跳过时返回跳过原因,否则为空字符串 |
仅当条件判断(if、ifModify、ifNewBranch)导致任务被跳过时,skip 属性才会出现。
- name: use if
if: exit -1
exports:
skip: REASON
- name: tell last
# $REASON 的值为 if 这个字符串
script: echo $REASON解析输出中的自定义变量
CI 从标准输出流中按行识别 ##[set-output key=value] 格式的内容,自动解析到 result 对象中。
变量值编码
若变量值包含换行符 \n,可对变量值进行 base64 或 escape 编码:
| 编码方式 | 说明 |
|---|---|
| base64 | 值以 base64, 开始,系统做 base64 解码 |
| escape | 系统对变量值做 unescape 解码 |
方式一 — Node.js(需 test.js 文件,同时输出 base64 和 escape):
main:
push:
- docker:
image: node:20-alpine
stages:
- name: set output env
script: node test.js
exports:
redline_msg_base64: BASE64_KEY
redline_msg_escape: ESCAPE_KEY
- name: echo env
script:
- echo "BASE64_KEY $BASE64_KEY"
- echo "ESCAPE_KEY $ESCAPE_KEY"方式二 — Shell echo(纯 Shell,无需脚本文件,仅输出 base64):
main:
push:
- stages:
- name: set output env
script: echo "##[set-output redline_msg_base64=base64,$(echo -e "测试字符串\ntest string" | base64 -w 0)]"
exports:
redline_msg_base64: BASE64_KEY
- name: echo env
script:
- echo "BASE64_KEY $BASE64_KEY"Node.js 脚本(test.js,用于上述方式一):
const value = '测试字符串\ntest string';
console.log(`##[set-output redline_msg_base64=base64,${Buffer.from(value, 'utf-8').toString('base64')}]`);
console.log(`##[set-output redline_msg_escape=${escape(value)}]`);注意
在 Unix-like 系统中,base64 命令默认会在每 76 个字符后添加一个换行符,可使用 -w 0 选项来禁用换行避免 CI 未能按行解析出变量。
不包含 \n 的变量值可直接输出:
echo "##[set-output redline_msg=some value]"限制说明
- 受限于系统环境变量值长度限制,过大的变量值无效
- CI 会忽略大于等于
100KB的变量值,可写入文件中自行解析 - 对于敏感信息,建议使用 read-file 内置任务
内置任务中导出环境变量
一些内置任务会有输出结果,可通过 exports 导出为环境变量。
main:
push:
- stages:
- name: xxxx
type: xxx:xxx
options:
product: public
name: cnb
dist: release/
exports:
version: CUSTOM_ENV_VERSION
url: CUSTOM_ENV_URL
nextRelease.gitTag: CUSTOM_ENV_GIT_TAG
- name: echo env
script:
- echo $CUSTOM_ENV_VERSION
- echo $CUSTOM_ENV_URLresult 内容参考各内置任务文档。
子流水线传递变量给父流水线
通过 cnb:apply(同仓库)或 cnb:trigger(跨仓库)触发的流水线,下称「子流水线」。 在 sync: true 同步模式下,其 result 会带回 lastJobExports——即子流水线最后一个 Job 通过 exports 导出的全部环境变量。 父流水线借此即可拿到子流水线的产出。
同步模式下 result 的主要属性:
| 属性 | 说明 |
|---|---|
| sn | 子流水线构建号 |
| buildLogUrl | 子流水线构建日志链接 |
| buildSuccess | 子流水线是否构建成功(仅同步模式存在) |
| lastJobExports | 子流水线最后一个 Job 导出的环境变量对象 |
注意
只有 sync: true 才会等待子流水线执行完成并带回 lastJobExports;异步模式下父流水线不等待,也拿不到这些结果。
示例:子流水线输出并导出一个变量,父流水线同步触发后取回使用。
main:
api_trigger_test:
- stages:
- name: 子流水线输出变量
script: echo "##[set-output sub_result=base64,$(echo -e "测试字符串\ntest string" | base64 -w 0)]"
exports:
sub_result: SUB_RESULT
push:
- stages:
- name: 触发子流水线并等待
type: cnb:apply
options:
event: api_trigger_test
sync: true
exports:
lastJobExports: SUB_EXPORTS
lastJobExports.SUB_RESULT: SUB_RESULT
sn: SUB_SN
- name: 使用子流水线传回的变量
script: |
echo "SUB_EXPORTS: $SUB_EXPORTS"
echo "SUB_SN: $SUB_SN"
echo "SUB_RESULT: $SUB_RESULT"跨仓库场景把 cnb:apply 换成 cnb:trigger 并指定目标仓库 slug 即可,取回变量的方式相同。
增删改查环境变量
不支持直接修改;设为空字符串或 null 即可删除。
main:
push:
- env:
CUSTOM_ENV_DATE_INFO: default
CUSTOM_ENV_FOR_DELETE: default
stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
# 新增
code: CUSTOM_ENV_DATE_CODE
# 修改
info: CUSTOM_ENV_DATE_INFO
# 删除
CUSTOM_ENV_FOR_DELETE: null
# 删除
# CUSTOM_ENV_FOR_DELETE:
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFO
- echo $CUSTOM_ENV_DATE_STDOUT
- echo $CUSTOM_ENV_FOR_DELETE
- echo $CUSTOM_ENV_GIT_TAG使用环境变量
在脚本任务中使用
当任务执行时,流水线声明的环境变量会作为任务的环境变量传入。以下示例中 CNB_BRANCH 为内置环境变量:
main:
push:
- stages:
- name: test internal env
script: echo $CNB_BRANCH
- name: test self defined env
env:
cat_name: tomcat
script: echo $cat_name变量替换
配置文件中的一些属性值会进行变量替换。
替换规则:如有环境变量 env_name=env_value,则属性值中的 $env_name 会被替换为 env_value;若 env_name 无值,则替换为空字符串。
支持变量替换的属性
| 属性 | 说明 |
|---|---|
| 内置任务 options | options 和 optionsFrom |
| 插件任务 settings | settings 和 settingsFrom |
| env | 可引用上层 env 中的变量 |
| imports | imports 及声明文件中的属性值 |
| pipeline.runner.tags | 构建节点标签 |
| pipeline.docker | volumes、image 和 build |
| stage.image 和 job.image | 环境镜像配置 |
| ifModify | 文件变更条件 |
| name | pipeline.name、stage.name 和 job.name |
| lock.key | 锁的键名 |
| allowFailure | 允许失败配置 |
内置任务示例
# options.yml
name: Nightlymain:
push:
- env:
address: options.yml
description: publish for xx task
stages:
- name: git release
type: git:release
optionsFrom: $address
options:
description: $descriptionoptions 的最终内容:
name: Nightly
description: publish for xx task插件任务示例
# settings.yml
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxmain:
push:
- env:
address: settings.yml
message: pr check
stages:
- name: notify
image: tencentcom/wecom-message
settingsFrom: $address
settings:
content: $messagesettings 的最终内容:
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
message: pr checkDockerfile 中的 settingsFrom
写在 Dockerfile 中的 LABEL 指定的 settingsFrom 同样可以进行变量替换:
FROM node:20
LABEL cnb.cool/settings-from="$address"env 示例
env 下声明的属性值可以引用上层 env 中的变量进行替换。以下示例中 $cat_name 会被替换为上层的 tomcat:
main:
push:
- env:
cat_name: tomcat
stages:
- name: echo env
env:
name: "cat $cat_name"
script: echo $nameimports 示例
imports 的属性值以及所声明的文件中的属性值均会进行变量替换。若 imports 为数组,数组前面文件中声明的变量对数组后面元素有效。
以下示例中 env1.yml 声明了 address: env2.yml,$address 会被替换为 env2.yml,进而导入 env2.yml 中的变量:
# env1.yml
address: env2.yml
platform: amd64# env2.yml
action: build for $platformmain:
push:
- imports:
- env1.yml
- $address
stages:
- name: echo action
script: echo $actionpipeline.runner.tags 示例
# 构建不同架构下的镜像
.build: &build
runner:
tags: cnb:arch:$CNB_PIPELINE_NAME
services:
- docker
stages:
- name: docker build
script: echo "docker build for $CNB_PIPELINE_NAME"
main:
push:
# 下面 "amd64" 和 "arm64:v8" 会被声明为内置环境变量 CNB_PIPELINE_NAME 的值
amd64: *build
"arm64:v8": *buildpipeline.docker 示例
main:
push:
- docker:
image: node:22-alpine
volumes:
- /data
stages:
- name: echo
script: echo "building with docker"ifModify 示例
# 不同模块下代码有变更才进行对应模块的编译
.build: &build
ifModify: $CNB_PIPELINE_NAME/*
stages:
- name: build $CNB_PIPELINE_NAME
script: echo "build $CNB_PIPELINE_NAME"
main:
push:
module-a: *build
module-b: *buildname 示例
pipeline.name、stage.name 和 job.name 的属性值会进行变量替换:
main:
push:
- name: build in $CNB_REPO_SLUG
env:
platform: amd64
imports:
- env1.yml
- env2.yml
stages:
- name: stage_$SOME_ENV
script: echo "hello world"lock.key 示例
# env.yml
build_key: build key.build: &build
imports: env.yml
lock:
key: $build_key
stages:
- name: echo
script: echo "hello world"
main:
push:
# 以下两条流水线,一条占用了锁成功执行,另一条位占到锁执行失败
- *build
- *buildallowFailure 示例
main:
push:
- env:
allow_fail: true
stages:
- name: echo
allowFailure: $allow_fail
script: echo1 1阻止变量替换
如果不希望 $env_name 被替换,可以通过 \$ 阻止替换:
main:
push:
- stages:
- name: git release
type: git:release
options:
name: Development
description: some code update \$description限制说明
环境变量有以下限制:
| 限制项 | 说明 |
|---|---|
| 变量名格式 | 仅支持字母、数字和下划线,不能以数字开头 |
| 变量值长度 | 不能超过 100KiB |
注意
不符合上述规则的变量会被忽略。
代理环境变量自动同步
当流水线在 Docker 容器中执行时,以下代理相关环境变量会自动从 Runner 宿主机同步到容器内, 无需在 .cnb.yml 中手动声明:
| 变量名 | 说明 |
|---|---|
HTTP_PROXY | HTTP 代理地址 |
HTTPS_PROXY | HTTPS 代理地址 |
NO_PROXY | 不走代理的地址列表 |
http_proxy | HTTP 代理地址(小写) |
https_proxy | HTTPS 代理地址(小写) |
no_proxy | 不走代理的地址列表(小写) |
取值规则
未在 env 中声明时,这些代理变量会自动继承 Runner 宿主机的配置,无需手动设置; 如在 env 中声明,则以用户声明的值为准。