简介
GitHub Actions创建CI/CD管道的核心组件是一个叫做工作流的东西。工作流是你可以在你的版本库中设置的流程,以运行自动化任务,如构建、测试、刷新、发布和部署
CI(持续集成)
的严格定义和该术语在业界的使用方式有很大不同。一个有影响力但相当早的(2006年)关于这个话题的讨论是在Martin Fowler’s blog。严格来说,CI指的是经常将开发人员的修改合并到主分支中。保持我们的代码干净和可维护。
通常有以下一些步骤:
- 检查代码: 保持我们的代码的干净和可维护性
- 构建: 构建生产版本
- 测试: 确保不会破坏现有功能
- 打包: 打包到一个版本
- 上传/部署: 上传/部署到服务器
这个过程应该被严格定义。通常,严格的定义是对创造力/开发速度的一种限制。然而,对于CI来说,这通常不应该是真的。这种严格性应该以允许更容易开发和合作的方式来设置。使用一个好的CI系统(比如我们将在这部分介绍的GitHub Actions)将使我们能够自动地完成这些工作。
CD连续交付和连续部署
连续交付
和连续部署
(两者的首字母缩写都是CD
)经常被用于谈论也负责部署的CI。(参考Wikipedia或另一篇Martin Fowler的博文),但一般来说,我们把CD称为主分支始终保持可部署的做法。一般来说,这也经常与由合并到主分支所引发的自动部署结合起来。CI和CD之间的模糊区域如何处理?例如,如果我们在任何新代码被合并到主干分支之前必须运行测试,那么这是CI,因为我们经常合并到主干分支,还是CD,因为我们要确保主干分支总是可以部署的?所以,有些概念经常跨越CI和CD之间的界限,可以将CD视为CI的一部分。
重要原则
重要的是要记住,CI/CD不是目标。目标是更好、更快的软件开发,减少可预防的错误和更好的团队合作。为此,CI应该始终根据手里的任务和项目本身进行配置。最终目标应始终铭记在心。你可以把CI看成是这些问题的答案。如何确保在所有将要部署的代码上运行测试?如何确保主分支在任何时候都是可部署的?如何确保构建是一致的,并且总是在它要部署的平台上工作?如何确保这些变化不会相互覆盖?如何在点击按钮时进行部署,或者在一个分支合并到主分支时自动部署?
工作流
每个工作流必须指定至少一个作业,其中包含一组步骤来执行单个任务。作业将被并行运行,每个作业中的步骤将被按顺序执行。
步骤可以从运行自定义命令到使用预先定义的行动,因此被称为GitHub Action
语法结构
在YAML文档中,一个基本的工作流程包含三个元素。这三个元素是
name:工作流的名称
on:触发该工作流执行的事件
jobs:工作流将执行的独立作业(一个基本的工作流可能只包含一个jobs)
示例
# 名称为Hello World!的工作流
name: Hello World!
# 触发器是推送到主分支,在我们的项目中被称为master。(你的主分支可以叫main或master)。
on:
push:
branches:
- master
# 有一个名为hello_world/job的工作,它将在Ubuntu 20.04的虚拟环境中运行。
jobs:
hello_world_job:
runs-on: ubuntu-20.04
# 这个作业只有一个步骤,名为 "Say hello",它将在shell中运行echo "Hello World!"命令。
steps:
- name: Say hello
run: |
echo "Hello World!"
创建工作流
在工程文件夹根目录创建.github/workflows/build.yaml
以我当前的React项目为例(构建生产文件):
name: Deployment pipeline
on:
push:
branches:
- main
jobs:
simple_deployment_pipeline:
runs-on: ubuntu-20.04
steps:
# uses指定运行一个特定的动作
# Action是一段可重复使用的代码,就像一个函数。Action可以在你的版本库中定义为一个单独的文件,也可以使用公共版本库中的Action
# 公共动作actions/checkout,指定版本(@v3),避免在动作被更新时可能出现的破坏性变化。作用:从git检查项目的源代码。
- uses: actions/checkout@v3
# 应用是用JavaScript编写的,需要设置Node.js,可以使用actions/setup-node 动作。版本16被选中,因为它是应用在生产环境中使用的版本。
- uses: actions/setup-node@v2
# with关键字被用来给动作提供一个 "参数"
with:
node-version: '16'
- name: install dependence
run: npm install
- name: build
run: npm run build
推送至远程仓库后,GitHub的Action选项开始执行工作流
构建完成,此处为最简单示例,更多触发工作流程,参考GitHub Action
的文档。
笔记
任何可能出错的事情都会出错。
墨菲定律
的一个措辞说到“任何可能出错的事情都会出错。”
如果我的电脑在部署过程中崩溃或挂起怎么办?
我连接到服务器并通过互联网进行部署,如果我的互联网连接中断了会怎样?
如果我的部署脚本/系统中的任何特定指令失败会怎样?
如果由于某种原因,我的软件在我部署的服务器上不能按预期工作,会发生什么?我可以回滚到以前的版本吗?
如果一个用户在我们进行部署之前对我们的软件做了一个HTTP请求(我们没有时间向用户发送响应)会发生什么?
这些只是部署过程中可能出错的一小部分,或者说,我们应该计划的事情。无论发生什么,我们的部署系统都不应该***我们的软件处于破碎状态。我们也应该总是知道(或者很容易找到)一个部署处于什么状态。
当涉及到部署(和一般的CI)时,要记住的另一个重要规则是。
“无声的失败是***糟糕的!”
这并不意味着故障需要显示给软件的用户,它意味着如果有什么问题,我们需要意识到。如果我们意识到一个问题,我们就可以修复它,如果部署系统没有给出任何错误,但却失败了,我们可能最终会陷入这样一种状态:我们认为我们已经修复了一个关键的错误,但部署却失败了,把这个错误留在了我们的生产环境中,而我们却没有意识到这种情况。
代码的主分支应该始终保持绿色。
绿色意味着你的构建管道的所有步骤都应该成功完成:项目应该成功构建,测试应该无误运行,并且linter不应该有任何产生警告,等等。
为什么这很重要?你可能会专门从主分支将代码部署到生产中。主分支中的任何故障都意味着在问题解决之前,新功能无法部署到生产中。有时,你会在生产中发现一个讨厌的错误,而CI/CD管线却没有发现。在这种情况下,你希望能够以安全的方式将生产环境回滚到之前的提交。
那你如何保持主分支的绿色?避免将任何修改直接提交到主分支。相反,在一个基于主分支的最新版本的分支上提交代码。一旦你认为该分支可以合并到主分支,你就创建一个 GitHub 拉动请求(也被称为 PR)