使用 GitHub Actions 构建良好的 CI/CD 流水线 它不再是“有时间再做”的额外步骤:在现代团队中,它几乎是快速可靠部署的必备条件。即便如此,找到一个完整、通用且经过深思熟虑的、可以应用于贵公司的示例,通常比看起来要复杂得多。
接下来,我们将融合经典的CI/CD理论。 通过 GitHub Actions、可重用管道、任务、bash 脚本等实际应用示例, PowerShell PnP 模块本文介绍了如何在 Kubernetes、Google Cloud 和 Kinsta 上部署,以及安全、监控和可扩展性的最佳实践。您可以根据自身情况灵活运用这些内容,从而避免许多常见的陷阱。
为什么你需要一个完善的 CI/CD 流水线
在当前的专业发展中,持续改进/持续发展(CI/CD)是规范的循环系统。它能够整合变更、运行测试、构建工件,并以最小的人工干预部署新版本。如果没有这种工作流程,每次部署都会变成缓慢、容易出错且繁琐的手动操作。
持续集成 (CI) 侧重于验证变更。 代码上传到代码仓库后,系统会立即运行单元测试、代码检查和静态分析,以便尽快发现并修复 bug。反馈越快,修复速度就越快,回归带来的损失也就越小。
持续部署(CD,指持续部署) 或者持续交付(取决于自动化程度)增加了发布部分的自动化:构建镜像、发布软件包、部署到测试、预发布或生产环境,甚至使用蓝绿或金丝雀策略来改变流量。
在拥有大量遗留代码的公司中良好的流水线是实现生态系统现代化的最佳杠杆之一:它允许您将测试引入遗留服务,自动化以前手动完成的任务,并降低维护 Jenkins 或 Nexus 等已过时的基础设施的成本。
什么是 GitHub Actions?为什么它与 CI/CD 如此契合?
GitHub Actions 是 GitHub 内置的自动化平台。 它允许你在代码仓库内部的 YAML 文件中定义工作流程。有了它,你无需设置外部 CI 服务器即可编译、测试、分析和部署软件。
工作流程是一系列作业和步骤的集合。 它是由以下事件触发的: push, pull_request, schedule (CRON), workflow_dispatch (手动)或针对问题的操作。每个作业都在一个运行器中运行(例如, ubuntu-latest它由使用可重用操作或命令的步骤组成 run.
GitHub 提供了一个庞大的股票交易市场。 这里几乎包含了所有现成的集成:Docker、Kubernetes、AWS、Azure、Google Cloud、SonarCloud、Slack、Jira、安全分析、上千种语言的代码检查器等等。这大大减少了设置高级管道所需的时间。
与 Jenkins 或 Concourse 等解决方案相比GitHub Actions 有几个明显的优势:它是一种托管服务(无需管理服务器),与代码紧密集成,采用按需付费模式,并且拥有庞大的社区支持。此外,许多开发者已经通过个人项目熟悉了它,这大大降低了学习难度。
GitHub Actions 工作流的基本组成部分
一切都始于一个 YAML 文件。 .github/workflows/, 例如 ci.yml o build-test-deploy.yml虽然语法可能会变得相当复杂,但基本结构相对简单。
YAML 的关键组成部分包括: name (工作流名称), on (触发它的事件) jobs (一系列逻辑任务),并且在每个任务中, runs-on (跑步者), steps (步骤) env (全局变量)和 if (执行步骤或作业的条件)。
工作岗位代表着一系列工作。 可以并行运行或链式运行 needs在每个作业中,步骤都使用操作(uses:)或命令(run:一个典型的例子包括:代码检出、依赖项安装、代码检查执行、测试和构建。
秘密和环境变量 它们在存储库、组织或环境级别进行管理。在工作流中,它们通过以下方式引用: ${{ secrets.MI_SECRET }} 并允许使用 API 密钥、部署令牌或云凭证,而无需将其暴露在存储库中。
YAML 还允许构建执行数组。 同 strategy.matrix这对于在各种版本的 Node、Python 或 Java 上,甚至在不同的操作系统上测试代码非常有用,而无需多次编写相同的代码块。
使用最佳实践设计现代化的 CI/CD 流水线
一个健康的生产流程通常分为清晰的阶段。快速检查(lint、单元测试)、制品构建、发布(版本、标签、变更日志、在制品库中发布)以及在一个或多个环境中部署。
持续集成阶段应该尽可能快。 这样可以确保任何推送或拉取请求都能立即得到反馈。一种常见的做法是使用单独的数组或作业并行运行各种检查,虽然成本略高,但可以减少整体等待时间。
将管道与具体语言解耦您可以使用 Task 之类的任务工具(类似于 Make,但语法更友好)。这样,GitHub Actions 工作流就只会调用通用任务(task test, task lint等等)并且每个存储库都根据它是 Node、Java、Python 等而定义了它们在内部是如何实现的。
版本控制和制品在发布阶段发挥作用。在这里,您可以构建 Docker 镜像、jar/war 文件、npm 包或任何其他工件,并将其上传到相应的注册表(Docker 注册表、Maven、Artifact Registry 中的 npm 等),标记提交,并使用诸如 GitHub Releases 之类的工具生成发布版本或变更日志。 git-cliff 或发布操作。
最后,进入部署阶段。 将该工件移至运行时环境:Kubernetes (GKE)、Google App Engine、Cloud Functions、Kinsta 上的服务、通过 SSH 部署到您自己的服务器等。您可以在此处链接后续步骤,例如部署后的功能测试或包含发布详情的 Slack 通知。
示例:包含 ESLint、测试和 Kinsta 部署的完整流水线
一个非常典型的例子是使用 GitHub Actions。 使用 ESLint 和单元测试验证 React 应用程序,然后使用 Kinsta 的 API 将其部署到 Kinsta。所有操作都在一个 CI/CD 工作流程中完成。
YAML的第一部分定义了触发器 以及管道名称。例如,它在每个 push y pull_request 分支 main甚至可以使用该事件通过 CRON 作业进行定时任务(例如,每天午夜或每周一 UTC 时间 8:00)。 schedule.
流程中的第一个工作可以称为 eslint 它负责检查代码语法。它运行在…… ubuntu-latest 并使用一系列 Node 版本(例如,18.x、20.x),以及检出和配置 Node 的步骤。 actions/setup-node缓存 npm 依赖项,使用以下命令安装 npm ci 扔 npm run lint.
第二份工作, tests这取决于 eslint 通过 needs: eslint因此,它仅在语法检查成功时运行。其内部重复执行以下模式:检出、依赖项安装和执行。 npm run test 在特定版本的Node上。
第三份工作, deploy它与两项工作都相关 运用 needs: 并使用了一个步骤 curl 调用 Kinsta API。为此,API 密钥和应用程序 ID 已配置为 GitHub 中的密钥(KINSTA_API_KEY y APP_ID)并在工作中通过以下方式暴露出来 env 构建触发部署的 POST 请求。
了解这项部署作业非常重要 Kinsta 将 API 被接受视为成功;然而,如果部署随后在 Kinsta 内部失败,GitHub 工作流仍可能显示绿色状态。应牢记这一点,避免掉以轻心,并辅以部署后监控流程。
高级 cron 管理和工作流调度
GitHub Actions 中的 CRON 语法 它基于 UNIX 五字段格式:分钟、小时、日期(月份)、月份和星期几。每个字段都可以使用 星号、范围、列表和步骤 (*, 1-5, 1,15,30, */5),从而可以安排维护任务、备份、清洁或定期检查。
例如: 0 0 * * * 每天午夜执行工作流程 (UTC),而 0 8 * * 1 它每周一早上 8:00 执行此操作。这与通常的触发器无缝结合。 push y pull_request这样,同一个 YAML 文件就可以对代码更改和计划执行做出反应。
此功能非常适合那些不适合在每次提交中都发布的任务。:进行密集的安全扫描(例如,使用 OWASP Dependency Check in Java)、依赖项审计、测试覆盖率检查或清理注册表中的旧工件。
工作流复用:将 CI/CD 扩展到数百个代码库
当你的组织拥有几十个或几百个存储库时到处复制粘贴相同的 YAML 文件只会造成混乱。任何改动都需要修改 GitHub Enterprise 的一半,这使得保持一致性和最佳实践几乎不可能。
解决方案在于设计可重用的工作流程。 集中存储在 CI/CD“模板”仓库中。这些工作流公开输入和输出,每个服务仅定义一个调用它们的简短 YAML 文件,传递诸如工件类型(Docker、Java 库、npm 包)、部署运行时(GKE、GAE、云函数等)或需要执行的任务项等参数。
一种常见的模式是将三个大型可重用工作流程分开。: 之一 build-check-task (持续集成),另一个 build-release-dockerfile 或其他工件和第三次部署(deploy-gke, deploy-gae等等),以便每个存储库通过将它们组合起来构建自己的管道。
为了封装共享逻辑,还可以定义自定义操作。 en .github/actions例如,配置 Gradle、Java、Node 或 Task,获取构建元数据,发布 Docker 镜像,使用 Bash 脚本在 Git 中标记版本,或向 Slack 发送通知。黄金法则是,服务仓库应该只使用可重用的工作流,而不是直接执行这些操作,这样才能更好地管理向后兼容性。
快速持续集成任务、矩阵和静态分析
在构建或检查阶段,建议并行触发多个操作。单元测试、静态分析(Java 中的 PMD、Checkstyle、SpotBugs;JS/TS 中的 ESLint)、使用 SonarCloud 进行扫描等。即使在大型代码库中,这也能保持总流水线时间的合理性。
任务(Taskfile.yml)充当抽象层。 在特定命令上,允许 CI 工作流简单地调用 task check, task test o task lint对于 Java 项目,这些任务可以委托给 Gradle,并使用 JUnit、PMD、Checkstyle 和 SpotBugs 等工具;对于 Node 项目,可以委托给 Jest、ESLint 以及诸如……之类的安全工具。 npm audit 或类似。
GitHub Actions 添加了数组部分 要在不同运行时版本上运行相同的任务,例如在 16、18 和 20 版本上测试 Node 库,或在 3.10 和 3.12 版本上测试 Python 项目,只需声明一个版本数组并在作业配置中使用它即可。
这种方法对于想要支持多种技术栈的组织来说尤其有用。 (Java、Node、TypeScript、Python 等)无需为每个存储库重写管道逻辑:任务适应每种语言,可重用的工作流程几乎保持不变。
发布阶段:版本控制、标签化和发布工件
检查通过后,就可以构建实际部署的工件了。Docker镜像、JAR文件、npm包,任何合适的形式都可以。这涉及到编程语言工具、组织机构的镜像仓库以及版本控制策略。
有些Java项目使用Gradle Axion之类的插件。 用于基于 Git 标签管理版本。在混合环境(Java、Node 等)中,使用自定义 bash 脚本可能更简单,该脚本可以计算下一个版本(例如使用 SemVer),创建标签,将其推送到远程仓库,并生成相应的发布版本。
像这样的工具 git-cliff 它们有助于生成变更日志。 根据提交信息,变更按类型(功能、修复、破坏性变更等)进行分类。将其集成到流水线中,可确保每次发布都附带清晰的变更日志,无需任何人手动编写。
要发布工件,需要结合适当的操作和凭证。Docker 镜像仓库(Docker Hub、GitHub Container Registry、Artifact Registry)、Maven 仓库、npm 镜像仓库等等。同样,凭据以密钥形式存储,仅在需要时才注入到作业中。
持续部署到 Kubernetes、GCP、Kinsta 和其他环境
部署是指 CI/CD 与基础设施交互的过程。在这里,GitHub Actions 可以与几乎任何平台无缝集成:Kubernetes、App Engine、云函数、传统服务器、Kinsta 等平台。
对于 Kubernetes(例如 GKE),通常遵循以下模式 具体操作如下:使用官方操作通过 Google Cloud 进行身份验证,并进行配置 kubectl 在集群环境中,应用 Helm 清单或图表,如有必要,执行受控发布(例如,使用金丝雀部署或蓝绿部署),并使用以下命令验证状态。 kubectl rollout status.
以 App Engine 或 Cloud Functions 为例该流水线构建镜像或工件,将其发布到工件注册表,然后调用部署命令。 gcloud 再次使用托管凭证(例如密钥和临时运行器)是合适的。
当部署是针对外部 API(例如 Kinsta 的 API)执行时通常一步就足够了 curl 或者执行一个特殊操作,该操作会发送包含身份验证令牌和必要参数(应用 ID、分支等)的请求。如果 API 对新版本发布请求做出正确响应,则该操作被视为成功。
部署过程几乎总会伴随通知。 发送到 Slack、Teams 或其他通信工具,注明部署了哪个服务、部署在哪个环境、版本号、触发者以及工作流日志链接。在生产环境中,这还有助于审计和追溯。
质量控制:安全、监控和日志
自动化构建和部署固然很好,但如果没有可见性就无法实现。 至于正在发生的事情,整个流程可能会变成一个黑匣子。GitHub Actions 提供按执行、作业和步骤划分的详细日志,使您能够诊断编译、测试或部署失败。
对于更高级的需求,我们集成了外部可观测性服务。 例如 Datadog、New Relic 或 Splunk 等工具,它们收集有关工作流、执行时间、故障率等的指标,帮助检测瓶颈并确定管道优化的优先级。
与此同时,安全也发挥着关键作用。:加密密钥管理、最小必要访问策略、操作权限审查、将代码漏洞扫描器和依赖项(代码扫描、密钥扫描、OWASP 等)集成到工作流程本身中。
许多团队还会增加部署后测试。 在新更新的环境中:端到端功能测试、性能检查、基本冒烟测试,以及,如果出现故障,则自动回滚机制可恢复到以前的稳定版本。
工作流治理:受保护的分支和拉取请求
处理分支和拉取请求的方式必须与持续集成/持续交付 (CI/CD) 保持一致。 这样一切就都说得通了。最常见的做法是保护主分支(main o master)并要求任何变更都必须通过 PR 并通过管道检查。
GitHub 允许您定义分支保护规则 这些策略强制使用拉取请求,阻止直接提交,并要求在允许合并之前,某些状态检查(特定的操作工作流)必须通过。它们可能还会要求最低修订版本数、审批规则等等。
该模型确保最终投入生产的代码符合生产环境的要求。 它经过了人工审核和所有自动化流程检查,大大降低了出现严重错误或漏洞的风险。
在拥有多种环境的公司中 (开发、测试、生产)部署到生产环境通常保留给合并到主分支的情况,而其他分支可能会触发部署到以前的环境进行内部测试或演示。
从宏观角度来看,一个设计良好的带有 GitHub Actions 的 CI/CD 流水线 它成为开发的核心:集成变更、运行全面的测试套件、构建和发布工件、部署到多个云平台、使用可观测性工具进行监控,并通过清晰的分支和拉取请求规则进行管理。凭借可重用的工作流、自定义操作、Task、Rease Action 和 Git Cliff 等辅助工具,以及强大的密钥和权限管理,它可以支持从简单的 Python 应用到复杂的 Kubernetes 架构的各种应用,在保证交付速度、代码质量和安全性的同时,避免团队被繁重的手动任务所困扰。