CI/CD
本文讲讲软件开发过程中的 CI/CD。
基本概念¶
在实际软件开发的过程中,代码会很频繁地变动,而代码变动就意味着需要重新「构建、测试和部署」,这是一个人力成本比较高、容易出错并且反馈周期较长的过程。
CI/CD 应运而生,它通过自动化流水线来解决上述问题。当代码提交到仓库后,系统自动触发构建、测试和部署,把“提交代码”到“可运行服务”的过程标准化、可重复化。其中:
- 持续集成 (Continuous Integration, CI) 侧重于尽早发现问题。通过频繁合并和自动测试,保证代码始终处于可工作的状态;
- 持续交付/部署 (Continuous Delivery / Deployment, CD) 侧重于尽快交付产品。让通过验证的代码可以随时、安全地发布到目标环境。
GitHub Actions¶
GitHub Actions 是 GitHub 原生提供的 CI/CD 平台,可用于自动执行生成、测试和部署管道。开发者可以创建工作流,以便在推送更改到存储库时运行测试,或将合并的拉取请求部署到生产环境。笔者目前只接触了 GitHub Action,所以就以它为例展开讲解。
从机制上看,GitHub Actions 的核心思想是:在代码仓库发生事件时,自动在一个隔离的运行环境中执行预先声明好的步骤。整个过程是声明式的,配置即行为。
GitHub Actions 在工程实践中价值很高,关键在于三点:
- 自动化是强制的,而不是约定的:只要事件发生,流程就一定会跑,避免“忘记跑测试”这种人为问题;
- 环境是一次性的,可复现的:每次运行都是全新环境,能暴露“只在我机器上能跑”的隐性依赖;
- 配置与代码同仓库演进:流水线规则随代码版本变化而变化,历史行为可追溯。
为了理解它的组成,可以把 GitHub Actions 拆解为以下几个关键概念。
工作流 / workflow¶
工作流是自动化的最外层单位,本质是一个 YAML 文件,放在仓库的 .github/workflows/ 目录下。一个仓库可以有多个工作流,每个工作流关注一类事情,例如 ci.yml 负责测试,release.yml 负责发布。
事件 / event¶
事件定义了“什么时候运行这个工作流”。常见事件包括代码推送 push、PR 创建 pull_request、包发布 release 等。事件只负责触发,不关心具体做什么。
任务 / job¶
一个工作流可以包含多个 job,job 之间默认并行执行,也可以通过依赖关系形成拓扑结构。每个 job 都会在一个独立的运行环境中执行。
步骤 / step¶
step 是 job 内的最小执行单元,可以直接执行命令,也可以调用一个已有的 action。step 按顺序执行,共享同一个文件系统上下文。
动作 / action¶
action 是可复用的步骤封装,可以理解为“流水线里的函数”。既可以使用 官方或社区提供的 action(通过 uses 使用);也可以在仓库中自定义(通过 run 进行)。注意 uses 和 run 这两个动作是原子操作,不能出现在同一个 step 中。
快速上手¶
CI/CD 需求
利用 GitHub Actions 将静态网站部署到 Aliyun OSS 上。这也是本网站 目前的部署方法 哟 😉。
直接看具体的工作流:
整个执行流程是:
-
on:有代码被推送或有 PR 被创建则触发工作流; -
jobs: main:启动一个名为 main 的工作:-
runs-on:基于 Ubuntu 运行环境; -
env:配置环境变量; -
steps:main 工作的具体步骤:- 拉取仓库代码;
- 配置 Python 环境;
- 配置 uv 包管理工具;
- 安装 Python 包依赖;
- 构建 Web 静态页面;
- 安装 Aliyun CLI;
- 配置 Aliyun CLI;
- 执行 Aliyun CLI 的一些命令。
如果任一步失败,job 立即终止,整个工作流标记为失败。
-
注意到在配置 Aliyun CLI 时有一个 ${{ <type>.<key> }} 语法。这是 GitHub Runner 引用用户额外配置的 GitHub Actions 变量的语法。GitHub Actions 仓库级变量一共有两类:
- 仓库私有变量。作为密文保存,可通过
${{ secrets.<private_var_name> }}的方式引用(同仓库的 Collaborator 可以看到,注意安全哟); - 仓库公开变量。作为明文保存,可通过
${{ vars.<public_var_name> }}的方式引用。
在仓库的 Settings 中的 Secrets and variables 中的 actions 中配置变量:
