从 GitHub Actions 迁移到 CNB
2250 字约 8 分钟
简介
GitHub Actions 和 CNB 都支持通过 YAML 配置文件定义自动化的构建、测试、发布和部署工作流,两者有一些相似之处:
- 工作流配置文件以 YAML 编写并存储在代码仓库中(CNB 中工作流称为流水线 Pipeline)
- 工作流包含一项或多项任务(CNB 中任务对应阶段 Stage)
- 任务包含一个或多个步骤或单个命令(CNB 中步骤对应任务 Job,每个任务可执行一系列命令或插件)
本指南将重点说明两者差异,以便您将 GitHub Actions 迁移到 CNB。
工作流配置
- GitHub Actions:每个工作流配置为单独的 YAML 文件,存放在
.github/workflows目录 - CNB:所有工作流配置存储在仓库根目录的 .cnb.yml 文件中(也可通过 include 关键字导入其他配置文件)
以下是两者语法的主要差异:
GitHub Actions 格式
name: Node.js CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests
run: npm testCNB 格式
.cnb.yml
main:
push: &build
- name: Node.js CI/CD
stages:
- name: build
image: ubuntu:latest
jobs:
- name: Run tests
script: npm test
pull_request: *build提示
注:&、* 是 YAML 语法,用于配置复用,详见 YAML 高级语法
构建触发规则
GitHub Actions 通过 on 字段定义触发规则,CNB 通过 触发分支 和 触发事件 来定义。详见 构建触发规则。
GitHub Actions 格式
name: Node.js CI/CD
on:
push:
branches: [main]
jobs:
build:
steps:
- name: echo
run: echo "do some job"CNB 格式
.cnb.yml
main: # 触发分支
push: # 触发事件,对应一个构建,可以包含多条 Pipeline。既可以是数组,也可以是对象。
- stages: # 流水线1
- name: echo
script: echo "do some job"Runners
- GitHub Actions 中 Runner 指执行任务的虚拟机(如
macOS、Windows、Linux) - CNB 中 Runner 指构建节点(默认运行 Docker 容器的节点),目前仅支持 Linux Docker 容器。企业版(私有化部署)可接入
macOS、Windows、Linux等不同机器,详见 构建节点
GitHub Actions 使用 runs-on 指定 Runner,CNB 使用 runner 字段指定构建节点的架构和资源配置。
GitHub Actions 格式
linux_job:
runs-on: ubuntu-latest
steps:
- run: echo "Hello, $USER!"CNB 格式
.cnb.yml
main:
push:
- runner:
tags: cnb:arch:amd64 # 指定在 amd64 架构构建节点上执行
cpus: 16 # 指定分配的CPU数为16核(内存数自动分配为 核数*2 GiB )
docker:
image: ubuntu:latest # 指定使用 ubuntu:latest 镜像作为流水线运行环境
stages:
- name: echo
script: echo "Hello, $USER!"构建环境
- GitHub Actions:工作流运行在虚拟机中,所需软件需预装或手动安装
- CNB:工作流运行在 Docker 容器中,只需指定镜像或 Dockerfile 即可搭建构建环境。详见 构建环境
GitHub Actions 格式
linux_job:
runs-on: ubuntu-latest
steps:
- name: Use Node.js 21
uses: actions/setup-node@v4
with:
node-version: 21
- run: npm ci
- run: npm run build --if-present
- run: npm testCNB 格式
.cnb.yml
main:
push:
- docker:
image: node:21 # 使用 node:21 作为流水线运行环境
stages:
- name: npm ci
script: npm ci
- name: build
script: npm run build --if-present
- name: npm test
script: npm test仓库代码准备
- GitHub Actions:使用
actions/checkout拉取仓库代码 - CNB:默认拉取仓库代码,无需显式声明。详见 流水线语法-仓库配置
GitHub Actions 格式
linux_job:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ls -al .CNB 格式
.cnb.yml
main:
push:
- stages:
- name: ls
script: ls -al .条件触发
- GitHub Actions:使用
if字段设置步骤执行条件 - CNB:使用
if、ifModify、ifNewBranch等字段设置步骤执行条件。详见 流水线语法-if
GitHub Actions 格式
jobs:
deploy_prod:
if: contains( github.ref, 'master')
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to production server"CNB 格式
.cnb.yml
$:
push:
- if: echo "$CNB_BRANCH" | grep -q 'master'
stages:
- name: Deploy to production server
script: echo "Deploy to production server"任务依赖
- GitHub Actions:使用
needs字段定义依赖关系 - CNB:使用
cnb:await和cnb:resolve内置任务定义依赖关系并传递变量。详见 await-resolve 内置任务
GitHub Actions 格式
jobs:
build_a:
runs-on: ubuntu-latest
steps:
- run: echo "This job will be run first."
build_b:
runs-on: ubuntu-latest
steps:
- run: echo "This job will be run first, in parallel with build_a"
test_ab:
runs-on: ubuntu-latest
needs: [build_a, build_b]
steps:
- run: echo "This job will run after build_a and build_b have finished"
deploy_ab:
runs-on: ubuntu-latest
needs: [test_ab]
steps:
- run: echo "This job will run after test_ab is complete"CNB 格式
.cnb.yml
main:
push:
- name: build_a
docker:
image: ubuntu:latest
stages:
- name: build_a
script: echo "This job will be run first."
- name: resolve for test_ab
type: cnb:resolve
options:
key: build_a
- name: build_b
docker:
image: ubuntu:latest
stages:
- name: build_b
script: echo "This job will be run first, in parallel with build_a"
- name: resolve for test_ab
type: cnb:resolve
options:
key: build_b
- name: test_ab
docker:
image: ubuntu:latest
stages:
- name: wait for build_a
type: cnb:await
options:
key: build_a
- name: wait for build_b
type: cnb:await
options:
key: build_b
- name: build_a
script: echo "This job will run after build_a and build_b have finished"
- name: resolve for test_ab
type: cnb:resolve
options:
key: test_ab
- name: deploy_ab
docker:
image: ubuntu:latest
stages:
- name: wait for test_ab
type: cnb:await
options:
key: test_ab
- name: deploy_ab
script: echo "This job will run after test_ab is complete"变量和密钥
- GitHub Actions:使用
env字段指定变量,使用secrets引用密钥 - CNB:使用
env字段指定变量,使用imports引用外部仓库或密钥 仓库文件作为环境变量。详见 引用变量 和 密钥仓库
GitHub Actions 格式
jobs:
deploy_prod:
runs-on: ubuntu-latest
env:
DEPLOYMENT_ENV: production
steps:
- run: echo "This job will deploy to the $DEPLOYMENT_ENV server"CNB 格式
#env.yml
DEPLOYMENT_ENV: "production".cnb.yml
main:
push:
- imports:
- cnb.cool/<your-repo-slug>/-/blob/main/xxx/env.yml
stages:
- name: Deploy to the $DEPLOYMENT_ENV server
script: echo "This job will deploy to the $DEPLOYMENT_ENV server"矩阵策略
- GitHub Actions:支持矩阵策略,在单个作业定义中基于变量组合自动创建多个作业运行
- CNB:不原生支持矩阵策略,但可使用 YAML 锚点功能模拟。详见 YAML 高级语法
GitHub Actions 格式
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [15.x, 16.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install node modules
run: npm install
- name: Run a one-line script
run: npm run build
- name: Run a multi-line script
run: npm run testCNB 格式
.cnb.yml
main:
push:
- docker:
image: node:14
stages: &BVT-testing-stages
- name: Install node modules
script: npm install
- name: Run a one-line script
script: npm run build
- name: Run a multi-line script
script: npm run test
- docker:
image: node:16
stages: *BVT-testing-stages缓存
- GitHub Actions:使用缓存策略暂存构建中间产物,供后续构建使用
- CNB:可通过
pipeline.runner.volumes声明节点本地缓存,或使用docker:cache内置任务声明远端 Docker 镜像缓存。详见 流水线缓存
GitHub Actions 格式
jobs:
deploy_prod:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Build project
run: npm ci && npm run buildCNB 格式
.cnb.yml
# 使用`pipeline.runner.volumes`声明`节点本地缓存`
main:
push:
- docker:
image: node:14
volumes:
- /root/.npm # 声明本地的缓存目录
stages:
- name: Build project
script: npm ci && npm run build.cnb.yml
# 使用`docker:cache`内置任务来声明`远端docker镜像缓存`
main:
push:
- docker:
image: node:14
stages:
- name: build cache image
type: docker:cache
options:
dockerfile: cache.dockerfile
# by 支持以下两种形式:数组、字符串
by:
- package.json
- package-lock.json
# versionBy: package-lock.json
versionBy:
- package-lock.json
exports:
name: DOCKER_CACHE_IMAGE_NAME
- name: use cache
image: $DOCKER_CACHE_IMAGE_NAME
# 将 cache 中的文件拷贝过来使用
commands:
- cp -r "$NODE_PATH" ./node_modules
- name: Build project
script: npm ci && npm run build其中 cache.dockerfile 是一个用于构建缓存镜像的 Dockerfile,示例:
# 选择一个 Base 镜像
FROM node:14
# 设置工作目录
WORKDIR /space
# 将 by 中的文件列表 COPY 过来
COPY . .
# 根据 COPY 过来的文件进行依赖的安装
RUN npm ci
# 设置好需要的环境变量
ENV NODE_PATH=/space/node_modules制品
- GitHub Actions:使用
actions/upload-artifact上传制品 - CNB:使用
cnbcool/attachments:latest插件上传制品,详见 附件插件
GitHub Actions 格式
jobs:
deploy_prod:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Upload a Build Artifact
uses: actions/upload-artifact@v2
with:
name: my-artifact
path: /path/to/artifactCNB 格式
.cnb.yml
main:
push:
- docker:
image: ubuntu:latest
stages:
- name: Upload a Build Artifact
image: cnbcool/attachments:latest
settings:
attachments:
- /path/to/artifact数据库及服务容器
- GitHub Actions:使用
services字段编排数据库及服务容器 - CNB:通过声明
docker服务,直接在任务中执行docker或docker compose命令编排。详见 Docker 服务
GitHub Actions 格式
jobs:
container-job:
runs-on: ubuntu-latest
container: node:20-bookworm-slim
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
steps:
- name: Check out repository code
uses: actions/checkout@v4
# Performs a clean installation of all dependencies
# in the `package.json` file
- name: Install dependencies
run: npm ci
- name: Connect to PostgreSQL
# Runs a script that creates a PostgreSQL client,
# populates the client with data, and retrieves data
run: node client.js
env:
# The hostname used to communicate with the
# PostgreSQL service container
POSTGRES_HOST: postgres
# The default PostgreSQL port
POSTGRES_PORT: 5432CNB 格式
.cnb.yml
# 直接在任务中使用`docker compose`命令,来编排数据库及服务容器
main:
push:
- docker:
image: ubuntu:latest
services:
- docker # 声明后,流水线容器会自动启动dind服务且主动注入docker cli工具
stages:
- name: Start database and service
script: docker-compose up -d
- name: Runs a script that creates a PostgreSQL client, populates the client with data, and retrieves data
script: node client.js
env:
POSTGRES_HOST: 127.0.0.1
POSTGRES_PORT: 5432