简单理解就是把代码测试、打包、发布等工作交给一些工具来自动完成。这样可以提高效率,减少失误,开发人员只需要关心开发和提交代码到git
就可以了。
CI,Continuous Integration,为持续集成。即在代码构建过程中持续地进行代码的集成、构建、以及自动化测试等;有了 CI 工具,我们可以在代码提交的过程中通过单元测试等尽早地发现引入的错误;
CD,Continuous Deployment,为持续交付。在代码构建完毕后,可以方便地将新版本部署上线,这样有利于快速迭代并交付产品。
不同的项目以及公司步骤可能不同。
常见的CI工具有很多,目前最为常用的是Jenkins。Jenkins包括一个master和很多个slave。master用于配置和组织节点、任务,slave则用来真正执行配置好的任务。因为用户群体的庞大,Jenkins上的各种插件,尤其是很多可视化插件都非常丰富,可以帮助很多新手快速配置所需的任务。
gitlab-ci是git官方的持续集成工具,在Git工程管理页面上,也有专门的CI配置和展示页。
GitLab CI/CD(后简称 GitLab CI)是一套基于 GitLab 的 CI/CD 系统,可以让开发人员通过 .gitlab-ci.yml 在项目中配置 CI/CD 流程,在提交后,系统可以自动/手动地执行任务,完成 CI/CD 操作。而且,它的配置非常简单,CI Runner 由 Go 语言编写,最终打包成单文件,所以只需要一个 Runner 程序、以及一个用于运行 jobs 的执行平台(如裸机+SSH,Docker 或 Kubernetes 等,我推荐用 Docker,因为搭建相当容易)即可运行一套完整的 CI/CD 系统
gitlab-ci是常见的CI平台。简单理解gitlab-ci是一个简易版的jenkins,git服务器兼任了Jenkins master的功能,而我们只需要准备好一个slave即可。而且,gitlab-ci的runner支持多重环境,尤其是Docker还有专属的配置支持。配置过程也非常的简便无脑,比起Jenkins的slave配置可以说是非常好用了。
Job为任务,是GitLab CI系统中可以独立控制并运行的最小单位。 在提交代码后,开发者可以针对特定的commit
完成一个或多个 job,从而进行CI/CD操作,每个Job都会配置一个stage属性,来表示这个Job所处的阶段
Pipeline 即流水线,可以像流水线一样执行多个 Job. 在代码提交或 MR 被合并时,GitLab 可以在最新生成的 commit
上建立一个 pipeline,在同一个 pipeline 上产生的多个任务中,所用到的代码版本是一致的
一般的流水线通常会分为几段;在 pipeline
中,可以将多个任务划分在多个阶段中,只有当前一阶段的所有任务都执行成功后,下一阶段的任务才可被执行。
整条流水线从左向右依次执行,每一列均为一个阶段,而列中的每个可操控元素均为任务。 左边两个阶段的任务是自动执行的任务,在commit提交后即可自动开始运行,执行成功或失败后,可以点击任务右边的按钮重试;而右边两个是手动触发任务,需要人工点击右边的“播放”按钮来手动运行。Pipeline是Gitlab根据项目的.gitlab-ci.yml文件执行的流程,由多个任务节点组成, 而这些Pipeline上的每一个任务节点,都是一个独立的Job。一个Pipleline有若干个stage,每个stage上有至少一个Job
在特定机器上根据项目的**.gitlab-ci.yml文件,对项目执行pipeline的程序**
使用webhooks
,这种方式的原理就是在gitlab
项目的Setting里的Integrations设置中
增加一个请求url
和一个secret
。具体可以登陆gitlab进行查看。如下图
当触发钩子条件时,(一般情况下是git push
之后),gitlab
会主动把secret
带在请求头中去请求前面的url
,后端服务接受到这个请求后并验证secret
后,就可以做各种事情了。这种方式不需要配置持续集成工具,但是需要自己单独专门写一个后端服务。前端主要使用下面的方式二,所以方式一的具体做法就不展开了。如果对webhooks感兴趣的话具体可以参考Gitlab Webhooks自动化部署实战
使用工具如
gitlab-CI
,这种方式的原理就是为项目在自己的服务器安装上注册gitlab-runner
,注册会有一个token
,服务器上运行gitlab-runner
后,runner
会轮询的发送带token
的http
请求给gitlab
,如果gitlab
有任务了,(一般是git push
),那么会把任务信息返回给runner
,然后runner
就开始调用注册时选的Executor
(也可以用shell
,看个人习惯)来执行项目根目录下的配置文件.gitlab-ci.yml
,执行后把结果反馈给gitlab
。
具体使用步骤如下:
在开发环境(如macOs上)开发前端项目(项目命名为ci-test
),并推送到gitlab
远程仓库中。这里用vue-cli 3.0
生成的vue
项目,可以添加如下自定义配置
//vue.config.js
module.exports = {
outputDir: 'app-page', //自定义打包后的目录名,注意在.gitnore文件中也要忽略掉该目录
baseUrl: './' //打包时使用相对路径
}
服务器上配置nginx
,并配置默认访问目录。例如配置是/app
文件夹
安装node
和git
,并在/app
目录下克隆gitlab
仓库中的代码,这时候服务器上就存在/app/ci-test
目录了
服务器上安装gitlab-runner
,可以根据自己需要安装,此处是mac下安装
runner可以理解为是Jenkins的slave,机器(或docker)通过runner程序与git服务器进行通信,当有新的任务发布到当前runner时,runner会执行.gitlab-ci.yml所定义的CI指令。
服务器上注册一个Runner
, 具体方法参考官方文档, 注意这里要填的url(一般是 https://gitlab.com)
和token
,都在gitlab
项目下的setting-CD/CD-Runners-Specific Runners
里,如下图
要填的tags
也是有用的,后面的.gitlab-ci.yml
里面的tag
选项必须是这里的tags
里面的子项(用来匹配任务和执行任务的runner,runner的tag可以有多个,注册时用逗号分隔即可),最后executor
这里也可以选择shell`,executor就是执行job的环境(executor:执行环境)
注册后修改gitlab-runner
的权限
sudo chown -R gitlab-runner:gitlab-runner /个人gitlab-runner安装路径/gitlab-runner
sudo chmod -R 777 /个人gitlab-runner安装路径/gitlab-runner
开启gitlab-runner
服务
gitlab-runner run // 运行成功的话,对应settings->CI/CD会出现一个绿点
在vue
项目根目录下配置.gitlab-ci.yml
文件,具体配置选项请看文档。
配置项 | 描述 |
---|---|
after_script | 覆盖作业后执行的一组命令 |
allow_failure | 允许作业失败。失败的作业不会导致管道失败 |
artifacts | 成功时附加到作业的文件和目录列表** |
before_script | 覆盖在作业之前执行的一组命令 |
cache | 应在后续运行之间缓存的文件列表 |
coverage | 给定作业的代码覆盖率设置 |
dependencies | 通过提供要从中获取工件的作业列表来限制将哪些工件传递给特定作业** |
environment | 作业部署到的环境的名称 |
except | 控制何时不创建作业 |
extends | 此作业继承自的配置条目 |
image | 使用 Docker 镜像** |
include | 包括外部 YAML 文件 |
inherit | 选择所有作业继承的全局默认值 |
interruptible | 定义当新的运行变得多余时是否可以取消作业 |
needs | 在阶段排序之前执行作业 |
only | 控制何时创建作业** |
pages | 上传作业的结果以与 GitLab 页面一起使用 |
parallel | 应该并行运行多少个作业实例 |
release | 指示跑步者生成一个释放对象 |
resource_group | 限制作业并发 |
retry | 在失败的情况下可以自动重试作业的时间和次数 |
rules | 用于评估和确定作业的选定属性以及它是否已创建的条件列表 |
script | 由运行程序执行的 Shell 脚本** |
secrets | CI/CD 隐藏作业所需的信息 |
services | 使用 Docker 服务镜像 |
stage | 定义作业阶段** |
tags | 用于选择跑步者的标签列表** |
timeout | 定义优先于项目范围设置的自定义作业级别超时 |
trigger | 定义下游管道触发器 |
variables | 在作业级别定义作业变量** |
When | 何时运行作业 |
将.gitlab-ci.yml
文件推送到gitlab
仓库中,在gitlab
项目页面中打开CI/CD-Pipelines
,即可看到效果,
status
那一列如果是绿色的passed
表示成功,以后每次只需要提交代码即可,再也不用手动测试部署了。
GitLab 允许在项目中编写 .gitlab-ci.yml
文件,来配置 CI/CD 流程
我们来编写一个简单的测试→构建→部署的 CI/CD 流程
首先定义流程所包含的阶段。我们的流程包含三个阶段:测试、构建和部署。
在 .gitlab-ci.yml 的开头,定义好所有阶段、以及执行每个任务之前所需要的环境变量以及准备工作,然后定义整个流程中包含的所有任务:
stages:
- test
- build
- deploy
variables:
IMAGE: docker.registry/name/${CI_PROJECT_NAMESPACE}-${CI_PROJECT_NAME}
before_script:
- IMAGE_TAG=${IMAGE}:${CI_COMMIT_SHA:0:8}
test:
image: "pymicro"
stage: test
services:
- name: mysql:5.6
alias: mysql
veriables:
MYSQL_DATABASE: db
MYSQL_ROOT_PASSWORD: password
before_script:
- pip install -U -r requirements.txt
script:
- flake8 app
- pytest tests
build:
image: "docker:17.11"
stage: build
services:
- name: "docker:17.12.0-ce-dind"
alias: dockerd
variables:
DOCKER_HOST: tcp://dockerd:2375
only:
- master
tags:
- build
script:
- docker build -t ${IMAGE_TAG} -f Dockerfile .
- docker push ${IMAGE_TAG}
deploy:
stage: deploy
variables:
GIT_STRATEGY: none
only:
- master
when: manual
tags:
- deploy-production
script:
- kubectl set image deploy/myproject "app=${IMAGE_TAG}" --record
在每个任务中,通常会包含 image, stage, services, script
等字段。
其中,stage 定义了任务所属的阶段;image 字段指定了执行任务时所需要的 docker 镜像;services 指定了执行任务时所需的依赖服务(如数据库、Docker 服务器等);而 script 直接定义了任务所需执行的命令。
具体说明:
测试:在测试任务中,启动了 MySQL 服务,并通过环境变量注入 MySQL 的初始数据库以及 Root 密码,在服务启动后,Runner 会运行 before_script
中的命令来安装所需依赖;安装成功后就会运行 script
属性中的命令来进行代码风格检查以及单元测试;MySQL 服务下有一个 alias
属性标识服务别名。如果Runner 运行在 Docker 平台下,可以直接通过服务别名访问到该测试环境中对应的服务。比如这个任务中,可以用 mysql://root:password@mysql/db
来访问测试数据库
构建:在构建任务中,会用 Dockerfile 注入依赖,将工程打包成 Docker 镜像并上传;为这个任务定义了一些额外的属性:tag 属性可以标记这个任务将在含有特定 tag 的 CI Runner 上运行;而 only 属性表示只有这个 commit 在特定的分支下(如 master)时,才可以在此 commit 上运行这个任务。在 before_scripts 中,通过环境变量拿到了项目所属的组,以及项目名称。GitLab 会在运行任务前,向环境中注入很多环境变量,来表明运行环境以及上下文。
部署:在部署任务中,会用 kubectl set image 命令将我们刚刚构建的镜像发布到生产环境。 when 表示运行该任务所需要的必要条件,如前一阶段任务全部成功。when: manual 表示该操作只允许手动触发。
.gitlab-ci.yml
常见配置项YML是一种编写配置文件的语言,比JSON更为简洁和方便。
下面我们看下简单的YML文件编写:
install-job: # 注释
tags:
- sss
stage: install
script:
- npm install
从上面代码中我们可以看出YML编写的一些特点:
YML中数组写法:
colors
- red
- blue
- yellow
// 相当于JSON中写法
{ "colors": ["red","blue","yellow"] }
YML中对象写法:
people:
name: zhangsan
age: 14
// 相当于JSON中写法
{
"people": {
"name": "zhangsan"
"age": 14
}
}
YML中对象和数组嵌套形式
a:
b:
- d
c: e
// 相当于JSON中写法
{
"a": {
"b": [ "d" ],
"c": "e"
}
}
例如:
stages:
- build
- test
- deploy
定义在YML文件的最外层,是一个数组,用于定义一个pipeline不同的流程节点
stages: # 所有阶段
- install
- eslint
- build
- deploy
由运行程序执行的 Shell 脚本,以项目根目录为上下文执行,是控制CI流程的核心,即安装、编译、部署的流程都是通过script定义的shell脚本来完成。
test:
script:
- 'curl --request POST --header "Content-Type: application/json" "https://gitlab/api/v4/projects"'
具体的某个阶段,是一个字符串,是stages数组的一个子项,表示当前的pipeline节点
build:
stage: build
后面跟的值是tag或者分支名的列表.
deploy:
stage: deploy
only:
variables:
- $CI_COMMIT_TAG
- $CI_COMMIT_NAME == "prod"
- tags
tags:
- k8s
使用标记从项目可用的所有运行器列表中选择特定的运行器。注册运行程序时,可以指定运行程序的标记,例如ruby、postgres、development。
build:
stage: build
tags:
- k8s
artifacts
将生成的资源作为pipeline运行成功的附件上传,并在gitlab交互界面上提供下载
build:
stage: build
script:
- 'npm run build'
artifacts:
name: 'bundle'
paths:
- build/
任务依赖。指定job的前置job。添加该参数后,可以获取到前置job的artifacts。注意如果前置 job 执行失败,导致没能生成artifacts,则 job 也会直接失败。
用于定义变量
可使用Docker的镜像和服务运行Job.image
是执行 CI/CD 依赖的 Docker 基础镜像。镜像中有 Node、Yarn、Dalp.
提高前端的开发效率和开发测试之间的协调效率
前端开发在提交代码之后就不用管了,ci流程会自动部署到测试或集成环境的服务器。很大程度上节约了开发的时间;同时,开发和测试人员可以共用gitlab里的pipeline界面, 测试同学能够随时把握代码部署的情况,同时还可以通过交互界面手动启动pipeline,自己去部署测试,从而节约和开发之间的沟通时间。
从更细的粒度把握代码质量
参考:
https://juejin.cn/post/6844903728546316295#heading-0
https://blog.csdn.net/bingfeilongxin/article/details/88326984
https://www.jianshu.com/p/30e3f2940078
https://zhuanlan.zhihu.com/p/184936276