脚本任务 vs 插件任务
1934 字约 6 分钟
概述
在 CNB 流水线中,Job(任务)是最小的执行单元,主要分为脚本任务、插件任务和内置任务三种类型。前两者都支持指定 image 参数定义运行环境,这容易让新人混淆。本文档将详细对比这两种任务类型的特点和使用场景,帮助你做出合适的选择。
相同点
执行环境
- 两者都可以指定
image参数来定义运行环境 - 都在独立的容器环境中执行,避免污染宿主或其他任务环境
环境变量
- 都可以使用 CNB 内置的系统环境变量,如
CNB_REPO_SLUG、CNB_COMMIT等
区别对比
核心差异
| 特性 | 脚本任务 | 插件任务 |
|---|---|---|
| 执行方式 | 以 image 作为执行环境,通过 script 或 commands 参数指定要执行的 Shell 命令 | 运行 image 中内置的 ENTRYPOINT 命令,可视为一个功能模块 |
| 默认环境 | 若不指定 image,则在流水线容器环境中执行 | 必须指定 image,运行插件镜像内置的入口命令 |
| 参数传递 | 通过 env 或 imports 声明或引入环境变量 | 通过 settings 指定参数,参数会以 PLUGIN_ 接参数名大写形式注入为环境变量 |
| 环境变量限制 | 无限制,可自由使用自定义环境变量 | 可使用 CNB 内置的系统环境变量,但通过 env 或 imports 声明或引入的自定义环境变量不会传递给插件 |
| 灵活性 | 灵活性高,用户可指定任意 Shell 命令 | 功能由插件开发者预设,通过 settings 配置 |
| 复用性 | 往往和业务强相关,使用限制较多 | 功能内聚易复用,可分享到插件市场 |
| 版本控制 | 脚本逻辑随代码仓库版本控制 | 若未指定 image 版本,默认使用 latest,插件更新可能导致已有流水线失败 |
详细说明
执行方式
脚本任务:以镜像作为执行环境,你拥有完全的控制权,可以执行任意 Shell 命令。
- name: install dependencies
image: node:20 # 指定执行环境,若不指定则在流水线容器环境中执行
script: npm install # 执行 Shell 命令
env:
NODE_ENV: production # 通过 env 声明环境变量插件任务:运行插件镜像中预设的 ENTRYPOINT 命令,通过 settings 参数配置插件行为。
- name: npm publish
image: plugins/npm # 运行插件镜像,执行内置的 ENTRYPOINT
settings:
username: $NPM_USER # 通过 settings 指定参数
password: $NPM_PASS
registry: https://registry.npmjs.org/上述插件任务会在环境中注入:
PLUGIN_USERNAMEPLUGIN_PASSWORDPLUGIN_REGISTRY
参数传递
脚本任务的环境变量传递:
- 通过
env声明环境变量 - 通过
imports从文件导入环境变量 - 优先级:
Job env>Stage env>Pipeline env
插件任务的参数传递:
- 通过
settings指定参数(参数会以PLUGIN_前缀注入环境变量) - 通过
settingsFrom从文件加载参数 - 通过
args传递命令行参数 - 注意:
env和imports声明的自定义环境变量不会传递给插件
环境变量限制
脚本任务:
- ✅ 可以使用
env声明的自定义环境变量 - ✅ 可以使用
imports导入的环境变量 - ✅ 可以使用 CNB 内置的系统环境变量
插件任务:
- ❌ 不能使用
env声明的自定义环境变量(不会传递) - ❌ 不能使用
imports导入的环境变量(不会传递) - ✅ 可以使用 CNB 内置的系统环境变量
- ✅ 可以通过变量替换在
settings和args中引用环境变量
# 正确:在 settings 中引用环境变量
- name: correct plugin usage
image: plugins/npm
settings:
username: $NPM_USER # ✅ 正确:引用环境变量进行变量替换
password: $NPM_PASS
# 错误:试图通过 env 传递参数给插件
- name: wrong plugin usage
image: plugins/npm
env:
PLUGIN_USERNAME: $NPM_USER # ❌ 错误:这不会传递给插件
PLUGIN_PASSWORD: $NPM_PASS最佳实践
1. 版本控制
插件任务:始终指定镜像版本,避免使用 latest 标签,防止插件更新导致流水线失败。
# 推荐:指定版本
- name: npm publish
image: plugins/npm:1.2.3
settings:
username: $NPM_USER
# 不推荐:使用 latest(插件更新可能导致配置失败)
- name: npm publish
image: plugins/npm # 默认使用 latest
settings:
username: $NPM_USER脚本任务:脚本逻辑随代码仓库版本控制,无需额外关注。
2. 安全性考虑
插件任务:
- 使用官方或可信的插件镜像
- 定期检查插件镜像的安全更新
- 在密钥仓库中存储敏感信息
脚本任务:
- 避免在脚本中硬编码敏感信息
- 使用环境变量传递密钥
- 使用密钥仓库管理配置
3. 复用性考虑
插件任务适合封装可复用的功能:
- 消息通知(企业微信、飞书、钉钉等)
- 通用 CI/CD 操作(发布、部署等)
- 代码质量检查(lint、扫描等)
这些功能可以发布到 CNB 插件市场,供其他开发者选用。
脚本任务适合业务相关的逻辑:
- 代码构建和测试
- 自定义数据处理
- 特定业务流程
这些逻辑往往与项目强相关,复用性较低。
4. 选择建议
| 场景 | 推荐类型 | 原因 |
|---|---|---|
| 通用 CI/CD 操作(发布、部署) | 插件任务 | 插件市场有成熟方案,易于复用 |
| 消息通知(企微、飞书、钉钉) | 插件任务 | 功能内聚,配置简单 |
| 代码构建和测试 | 脚本任务 | 灵活控制,适应各种构建工具 |
| 自定义业务逻辑 | 脚本任务 | 需要完全控制执行流程 |
| 调用外部 API | 脚本任务 | 灵活处理各种 API 格式 |
| 需要复用的通用功能 | 插件任务 | 可分享到插件市场 |
常见问题
Q1: 为什么插件任务不能通过 env 传递环境变量?
A: 插件任务的设计理念是功能模块化,通过 settings 明确定义插件接受的参数,而不是传递所有环境变量。这样做的好处是:
- 插件接口清晰,避免参数混乱
- 插件可以明确声明需要哪些参数
- 提高安全性和可维护性
Q2: 脚本任务不指定 image 会在哪里执行?
A: 脚本任务不指定 image 时,会在流水线容器环境中执行。流水线容器环境由 Pipeline.docker.image 或 Stage.image 指定。
main:
push:
- docker:
image: node:20 # 流水线容器环境
stages:
- name: without image
# 不指定 image,在 node:20 环境中执行
script: node -v
- name: with image
# 指定 image,在 python:3.9 环境中执行
image: python:3.9
script: python --versionQ3: 如何在插件任务中使用环境变量?
A: 在 settings 或 args 中使用变量替换。
- name: plugin with env
image: plugins/npm
settings:
username: $NPM_USER # 使用变量替换
password: $NPM_PASSQ4: 插件任务可以执行自定义脚本吗?
A: 插件任务的执行逻辑由插件镜像预设,不支持执行自定义脚本。如需执行自定义脚本,应使用脚本任务。
Q5: 如何判断应该使用脚本任务还是插件任务?
A: 问自己以下问题:
- 是否有现成的插件满足需求? → 使用插件任务
- 是否需要灵活执行自定义命令? → 使用脚本任务
- 功能是否可以复用和分享? → 考虑使用插件任务
- 功能是否与业务强相关? → 使用脚本任务
总结
脚本任务和插件任务各有优势:
- 脚本任务:灵活性高,适合自定义业务逻辑
- 插件任务:功能内聚,易于复用和分享
选择合适的任务类型可以简化配置、提高复用性,同时保持必要的灵活性。