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的工作流:
下图是DevOps生命周期中的各个阶段,可以看到持续交付是需要手动确认的,而持续部署则是自动的。
.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作业将并行启动并对文件运行测试。
示例中的完整流水线由三个作业组成,氛围两个阶段,build和test。每次将更改推送到项目中的任何分支的时候,流水线(pipeline)都会运行。
.gitlab-ci.yml关键字参考: docs.gitlab.cn/jh/ci/yaml/
CI/CD 流水线(pipeline)
流水线是持续集成、交付和部署的顶级组件。
流水线包括:
- 工作(job),定义做什么。例如:编译或测试代码的作业
- 阶段(stage),定义何时运行作业。例如:在编译代码的阶段之后运行测试的阶段
作业由runners执行。如果有足够多的并发运行程序,同一阶段的多个作业将并行执行。
如果一个阶段中的所有作业都成功,则流水线将进入下一个阶段。
如果某个阶段中的任何作业失败,则下一个阶段(通常)不会执行并且流水线会提前结束。
一般来说,流水线是自动执行的,一旦创建完毕之后就不再需要干预,但是,也可以手动与流水线交互。
一个典型的流水线可能包含四个阶段,按以下顺序执行:
- 一个
build阶段,有一个名为compile的作业 - 一个
test阶段,有两个名为test1和test2的作业 - 一个
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作业,需要:
- 注册一个runner,让所有的作业都在Docker容器中运行。在注册期间选择Docker executor
- 指定在哪个容器中运行作业。在
.gitlab-ci.yml文件中指定一个镜像 - 可选。在容器中运行其他服务,如MySQL。可以在
.gitlab-ci.yml文件中指定services
具体操作参考:docs.gitlab.cn/jh/ci/docke…
画龙项目里的CI/CD
具体配置在根目录下的.gitlab-ci.yml文件里。
通过查看该文件,发现项目的CI/CD共包含3个流程,分别是build,build-docker和deploy。
- build阶段:
- 在此阶段,会首先调用gf的docker,并设置相关运行环境为14.15.4版本的nodejs。除此之外,还规定了打包的输出路径为
dist/。此外,相关的脚本规定项目运行npm相关指令,包括npm cache clean,npm i以及npm run build:$BUILD_ENV - 此外还规定了dev分支为develop和web,而prod分支为master
- 在此阶段,会首先调用gf的docker,并设置相关运行环境为14.15.4版本的nodejs。除此之外,还规定了打包的输出路径为
- build-docker阶段:
- 首先提前定义了工作模版,里面记录了广发docker的地址,还提前写好了docker相关的脚本,包括:导出docker_token,使用docker_user和docker_token登陆远端docker,导出镜像IMAGE,然后使用docker build和docker push来生成并推出镜像
- 然后在
build-docker-dev和build-docker-master两个stage中直接调用先前定义好的工作模版
- deploy阶段:
- 和build-docker阶段一样,先定义好
.deploy_template模版。在该模版中,规定了镜像的名称,模版id(TemplateId),目标集群(TargetClusters)和相关容器(Container) - 在该模版的脚本中,定义了相关的TAG和PipeLineId
- 最后还规定了允许调用该模版的分支:develop、web和master
- 和build-docker阶段一样,先定义好