CI/CD学习笔记

513 阅读8分钟

GitLab CI/CD

GitLab CI/CD是一种使用持续方法进行软件开发的工具,它主要包含了三部分:

  • 持续集成(CI)
  • 持续交付(CD: continuous deliver)
  • 持续部署(CD: continuous deployment)

持续集成

持续集成的意思是指:开发人员每次推送代码到仓库时,可以通过创建一组脚本,自动地构建和测试应用程序。而这些脚本有助于减少在应用程序中引入错误的机会。

提交给应用程序的每个更改,甚至是开发分支,都会自动且连续地构建和测试。这些测试用来确保新提交的更改符合之前建立好的规范。

持续交付

持续交付(CD)是超越持续集成(CI)的一步。每次将代码更改推送到代码库时,不仅会构建和测试仓库的应用程序,还会持续地部署应用程序。但是持续交付不是自动的,而是需要人们手动地触发部署。

持续交付会自动检查代码,但需要人工干预以手动和战略性地触发更改的部署。

持续部署

持续部署是超越持续集成的又一步,类似于持续交付。不同之处在于,不再是手动地部署应用程序,而是将其设置为自动部署不需要人工干预

GitLab CI/CD工作流

GitLab CI/CD适合通用的开发工作流程。

可以先在本地仓库修改代码,然后,当这些修改被提交到远端分支的时候,会自动触发项目的CI/CD流水线(pipeline),之后,GitLab CI/CD会:

  • 运行自动化脚本(串行或并行)
    • 构建和测试应用程序
    • 在Review App中预览更改,就像在localhost上看到的一样

实施后按预期工作:

  • 审核并批准相关改动
  • 将功能分支合并到默认分支中
    • GitLab CI/CD 会将相关的更改自动部署到生产环境中去
    • 如果过程出现问题或未达到预期效果,还可以回滚相关的更改

下图展示了GitLab中CI/CD的工作流:

image.png

下图是DevOps生命周期中的各个阶段,可以看到持续交付是需要手动确认的,而持续部署则是自动的。

image.png

.gitlab-ci.yml文件

要是用GitLab CI/CD,需要:

  • 在GitLab仓库中托管应用程序代码
  • 仓库根目录中名为.gitlab-ci.yml的文件,其中包含CI/CD的配置

.gitlab-ci.yml文件中,可以定义:

  • 要运行的脚本
  • 要包含的其他配置文件和模版
  • 依赖项和缓存
  • 要按顺序运行的命令和要并行运行的命令
  • 要将应用程序部署到的位置

脚本会被分组到作业中,并且作业作为更大的流水线的一部分运行。可以将多个独立作业分组到按定义顺序运行的阶段。此外,CI/CD配置至少需要一项非隐藏的作业。

例:

    stages:
      - build
      - test
    
    build-code-job:
      stage: build
      script:
        - echo "Check the ruby version, then build some Ruby project files:"
        - ruby -v
        - rake
    
    test-code-job1:
      stage: test
      script:
        - echo "If the files are built successfully..."
        - rake test1
    
    test-code-job2:
      stage: test
      script:
        - echo "If the files are built successfully..."
        - rake test2

在这个例子中,build阶段的build-code-job作业会首先运行,它会输出作业使用的Ruby版本,然后运行rake来构建项目文件。如果此作业成功完成,则test阶段中的两个test-code-job作业将并行启动并对文件运行测试。

示例中的完整流水线由三个作业组成,氛围两个阶段,buildtest。每次将更改推送到项目中的任何分支的时候,流水线(pipeline)都会运行。

.gitlab-ci.yml关键字参考: docs.gitlab.cn/jh/ci/yaml/

CI/CD 流水线(pipeline)

流水线是持续集成、交付和部署的顶级组件。

流水线包括:

  • 工作(job),定义做什么。例如:编译或测试代码的作业
  • 阶段(stage),定义何时运行作业。例如:在编译代码的阶段之后运行测试的阶段

作业由runners执行。如果有足够多的并发运行程序,同一阶段的多个作业将并行执行

如果一个阶段中的所有作业都成功,则流水线将进入下一个阶段。

如果某个阶段中的任何作业失败,则下一个阶段(通常)不会执行并且流水线会提前结束。

一般来说,流水线是自动执行的,一旦创建完毕之后就不再需要干预,但是,也可以手动与流水线交互。

一个典型的流水线可能包含四个阶段,按以下顺序执行:

  • 一个build阶段,有一个名为compile的作业
  • 一个test阶段,有两个名为test1test2的作业
  • 一个staging阶段,有一个名为deploy-to-stage的作业
  • 一个production阶段,有一个名为deploy-to-prod的作业

流水线类型

流水线可以通过多种不同的方式进行配置:

  • 基本流水线:同时运行每个阶段的所有内容,然后是下一个阶段
  • 有向无环图(DAG)流水线:基于作业之间的关系自动调整,可以比基本流水线运行得更快
  • 多项目流水线:将不同项目的流水线结合在一起
  • 父子流水线:将复杂的流水线分解为一个可以触发多个子流水线的父流水线,这些子流水线都运行在同一个项目中并具有相同的SHA。这种流水线架构通常用于mono-repos
  • 合并请求的流水线:仅遇到合并请求时才触发(而不是针对每次提交)
  • 合并结果的流水线:是来自源分支的更改已经合并到目标分支的合并请求流水线
  • 合并队列:使用合并结果流水线将合并一个接一个地排队

自定义流水线配置参考:docs.gitlab.cn/jh/ci/pipel…

作业

流水线配置从作业开始。作业是.gitlab-ci.yml文件中最基本的元素

工作(job)是:

  • 定义了约束条件,说明它们应该在什么条件下执行
  • 具有任意名称的顶级元素,并且必须至少包含一个script子句
  • 不限制定义的数量

例:

    job1:
        script: "execute-script-for-job1"
    job2:
        script: "execute-script-for-job2"

该示例中具有两个单独的作业,其中每个作业执行不同的命令。作业都由runners拾取并在runners的环境中执行。需要注意的是:每个作业都是相互独立运行的。

流水线中的作业顺序

流水线中作业的顺序取决于流水线图的类型。

  • 对于完整流水线图,作业按名称排序
  • 对于流水线迷你图,作业按状态排序,然后按名称排序

作业状态的顺序是:

  • failed
  • warning
  • pending
  • running
  • manual
  • scheduled
  • canceled
  • success
  • skipped
  • created

Docker集成

将Docker合并到CI/CD的工作流程中有两种主要方法:

  • 在Docker容器中直接运行CI/CD作业
    • 例如,可以告诉GitLab CI/CD使用托管在Docker Hub或GitLab容器镜像库中的节点镜像。然后,将作业在基于镜像的容器中运行。该容器具有构建应用程序所需的所有Node依赖项。
  • 使用Docker或kaniko构建Docker镜像
    • 可以创建CI/CD作业来构建Docker镜像并将它们发布到容器镜像库。

在Docker容器中运行CI/CD作业

可以在单独的、隔离的Docker容器中运行CI/CD作业。

如果在本地机器上运行Docker,则可以在本地容器中运行测试,而不是在专用CI/CD服务器上进行测试。

要在Docker容器中运行CI/CD作业,需要:

  1. 注册一个runner,让所有的作业都在Docker容器中运行。在注册期间选择Docker executor
  2. 指定在哪个容器中运行作业。在.gitlab-ci.yml文件中指定一个镜像
  3. 可选。在容器中运行其他服务,如MySQL。可以在.gitlab-ci.yml文件中指定services

具体操作参考:docs.gitlab.cn/jh/ci/docke…

画龙项目里的CI/CD

具体配置在根目录下的.gitlab-ci.yml文件里。

通过查看该文件,发现项目的CI/CD共包含3个流程,分别是build,build-dockerdeploy

  • build阶段:
    • 在此阶段,会首先调用gf的docker,并设置相关运行环境为14.15.4版本的nodejs。除此之外,还规定了打包的输出路径为dist/。此外,相关的脚本规定项目运行npm相关指令,包括npm cache clean, npm i以及npm run build:$BUILD_ENV
    • 此外还规定了dev分支为develop和web,而prod分支为master
  • build-docker阶段:
    • 首先提前定义了工作模版,里面记录了广发docker的地址,还提前写好了docker相关的脚本,包括:导出docker_token,使用docker_user和docker_token登陆远端docker,导出镜像IMAGE,然后使用docker build和docker push来生成并推出镜像
    • 然后在build-docker-devbuild-docker-master两个stage中直接调用先前定义好的工作模版
  • deploy阶段:
    • 和build-docker阶段一样,先定义好.deploy_template模版。在该模版中,规定了镜像的名称,模版id(TemplateId),目标集群(TargetClusters)和相关容器(Container)
    • 在该模版的脚本中,定义了相关的TAG和PipeLineId
    • 最后还规定了允许调用该模版的分支:develop、web和master