CI/CD工作流


简介

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

workflows

推送至远程仓库后,GitHub的Action选项开始执行工作流

action

构建完成,此处为最简单示例,更多触发工作流程,参考GitHub Action文档

complete

笔记

  1. 任何可能出错的事情都会出错。

    墨菲定律的一个措辞说到

    “任何可能出错的事情都会出错。”

    如果我的电脑在部署过程中崩溃或挂起怎么办?

    • 我连接到服务器并通过互联网进行部署,如果我的互联网连接中断了会怎样?

    • 如果我的部署脚本/系统中的任何特定指令失败会怎样?

    • 如果由于某种原因,我的软件在我部署的服务器上不能按预期工作,会发生什么?我可以回滚到以前的版本吗?

    • 如果一个用户在我们进行部署之前对我们的软件做了一个HTTP请求(我们没有时间向用户发送响应)会发生什么?

    这些只是部署过程中可能出错的一小部分,或者说,我们应该计划的事情。无论发生什么,我们的部署系统都不应该***我们的软件处于破碎状态。我们也应该总是知道(或者很容易找到)一个部署处于什么状态。

    当涉及到部署(和一般的CI)时,要记住的另一个重要规则是。

  2. “无声的失败是***糟糕的!”

    这并不意味着故障需要显示给软件的用户,它意味着如果有什么问题,我们需要意识到。如果我们意识到一个问题,我们就可以修复它,如果部署系统没有给出任何错误,但却失败了,我们可能最终会陷入这样一种状态:我们认为我们已经修复了一个关键的错误,但部署却失败了,把这个错误留在了我们的生产环境中,而我们却没有意识到这种情况。

  3. 代码的主分支应该始终保持绿色

    绿色意味着你的构建管道的所有步骤都应该成功完成:项目应该成功构建,测试应该无误运行,并且linter不应该有任何产生警告,等等。

    为什么这很重要?你可能会专门从主分支将代码部署到生产中。主分支中的任何故障都意味着在问题解决之前,新功能无法部署到生产中。有时,你会在生产中发现一个讨厌的错误,而CI/CD管线却没有发现。在这种情况下,你希望能够以安全的方式将生产环境回滚到之前的提交。

    那你如何保持主分支的绿色?避免将任何修改直接提交到主分支。相反,在一个基于主分支的最新版本的分支上提交代码。一旦你认为该分支可以合并到主分支,你就创建一个 GitHub 拉动请求(也被称为 PR)


文章作者: 张登友
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 张登友 !
  目录