前端持续集成部署CI/CD

什么是持续集成/持续部署(CI/CD)?

简单理解就是把代码测试、打包、发布等工作交给一些工具来自动完成。这样可以提高效率,减少失误,开发人员只需要关心开发和提交代码到git就可以了。

CI/CD

CI,Continuous Integration,为持续集成。即在代码构建过程中持续地进行代码的集成、构建、以及自动化测试等;有了 CI 工具,我们可以在代码提交的过程中通过单元测试等尽早地发现引入的错误;

CD,Continuous Deployment,为持续交付。在代码构建完毕后,可以方便地将新版本部署上线,这样有利于快速迭代并交付产品。

CI的过程包括以下几个步骤

  1. 提交(合并)代码
  2. 编译
  3. 测试
  4. 发布

不同的项目以及公司步骤可能不同。

前端持续集成部署CI/CD_第1张图片

持续集成工具

常见的CI工具有很多,目前最为常用的是Jenkins。Jenkins包括一个master和很多个slave。master用于配置和组织节点、任务,slave则用来真正执行配置好的任务。因为用户群体的庞大,Jenkins上的各种插件,尤其是很多可视化插件都非常丰富,可以帮助很多新手快速配置所需的任务。

gitlab-ci是git官方的持续集成工具,在Git工程管理页面上,也有专门的CI配置和展示页。

前端持续集成部署CI/CD_第2张图片

GitLab CI/CD

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配置可以说是非常好用了。

Gitlab CI 的一些基本概念

job

Job为任务,是GitLab CI系统中可以独立控制并运行的最小单位。 在提交代码后,开发者可以针对特定的commit
完成一个或多个 job,从而进行CI/CD操作,每个Job都会配置一个stage属性,来表示这个Job所处的阶段

Pipeline

Pipeline 即流水线,可以像流水线一样执行多个 Job. 在代码提交或 MR 被合并时,GitLab 可以在最新生成的 commit
上建立一个 pipeline,在同一个 pipeline 上产生的多个任务中,所用到的代码版本是一致的

Stage

一般的流水线通常会分为几段;在 pipeline
中,可以将多个任务划分在多个阶段中,只有当前一阶段的所有任务都执行成功后,下一阶段的任务才可被执行。

CI Pipeline

整条流水线从左向右依次执行,每一列均为一个阶段,而列中的每个可操控元素均为任务。 左边两个阶段的任务是自动执行的任务,在commit提交后即可自动开始运行,执行成功或失败后,可以点击任务右边的按钮重试;而右边两个是手动触发任务,需要人工点击右边的“播放”按钮来手动运行。Pipeline是Gitlab根据项目的.gitlab-ci.yml文件执行的流程,由多个任务节点组成, 而这些Pipeline上的每一个任务节点,都是一个独立的Job。一个Pipleline有若干个stage,每个stage上有至少一个Job

Runner

在特定机器上根据项目的**.gitlab-ci.yml文件,对项目执行pipeline的程序**

怎么做呢?

方案一

使用webhooks,这种方式的原理就是在gitlab项目的Setting里的Integrations设置中增加一个请求url和一个secret。具体可以登陆gitlab进行查看。如下图

前端持续集成部署CI/CD_第3张图片

当触发钩子条件时,(一般情况下是git push之后),gitlab会主动把secret带在请求头中去请求前面的url,后端服务接受到这个请求后并验证secret后,就可以做各种事情了。这种方式不需要配置持续集成工具,但是需要自己单独专门写一个后端服务。前端主要使用下面的方式二,所以方式一的具体做法就不展开了。如果对webhooks感兴趣的话具体可以参考Gitlab Webhooks自动化部署实战

方式二:

使用工具如gitlab-CI,这种方式的原理就是为项目在自己的服务器安装上注册gitlab-runner,注册会有一个token,服务器上运行gitlab-runner后,runner会轮询的发送带tokenhttp请求给gitlab,如果gitlab有任务了,(一般是git push),那么会把任务信息返回给runner,然后runner就开始调用注册时选的Executor(也可以用shell,看个人习惯)来执行项目根目录下的配置文件.gitlab-ci.yml,执行后把结果反馈给gitlab

具体使用步骤如下:

  1. 在开发环境(如macOs上)开发前端项目(项目命名为ci-test),并推送到gitlab远程仓库中。这里用vue-cli 3.0生成的vue项目,可以添加如下自定义配置

    //vue.config.js
    module.exports = {
        outputDir: 'app-page',          //自定义打包后的目录名,注意在.gitnore文件中也要忽略掉该目录
        baseUrl: './'                   //打包时使用相对路径
    }
    
  2. 服务器上配置nginx,并配置默认访问目录。例如配置是/app文件夹

  3. 安装nodegit,并在/app目录下克隆gitlab仓库中的代码,这时候服务器上就存在/app/ci-test目录了

  4. 服务器上安装gitlab-runner,可以根据自己需要安装,此处是mac下安装

    runner可以理解为是Jenkins的slave,机器(或docker)通过runner程序与git服务器进行通信,当有新的任务发布到当前runner时,runner会执行.gitlab-ci.yml所定义的CI指令。

    前端持续集成部署CI/CD_第4张图片

  5. 服务器上注册一个Runner, 具体方法参考官方文档, 注意这里要填的url(一般是 https://gitlab.com)token,都在gitlab项目下的setting-CD/CD-Runners-Specific Runners里,如下图

前端持续集成部署CI/CD_第5张图片

​ 要填的tags也是有用的,后面的.gitlab-ci.yml里面的tag选项必须是这里的tags里面的子项(用来匹配任务和执行任务的runner,runner的tag可以有多个,注册时用逗号分隔即可),最后executor这里也可以选择shell`,executor就是执行job的环境(executor:执行环境)

  1. 注册后修改gitlab-runner的权限

    sudo chown -R gitlab-runner:gitlab-runner /个人gitlab-runner安装路径/gitlab-runner
    sudo chmod -R 777 /个人gitlab-runner安装路径/gitlab-runner
    
  2. 开启gitlab-runner服务

    gitlab-runner run // 运行成功的话,对应settings->CI/CD会出现一个绿点
    
  3. 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 何时运行作业
  4. .gitlab-ci.yml文件推送到gitlab仓库中,在gitlab项目页面中打开CI/CD-Pipelines,即可看到效果,

status那一列如果是绿色的passed表示成功,以后每次只需要提交代码即可,再也不用手动测试部署了。

  1. 浏览器中打开地址是:服务器地址/项目名(ci-test)/自定义打包目录(app)

GitLab Runner 使用流程

  1. 下载 GitLab Runner
  2. 注册 GitLab Runner
  3. 使用 GitLab Runner

CI/CD 流程配置

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常见配置项

CI/CD流程

  • 项目根目录下配置**.gitlab-ci.yml**文件,可以控制ci流程的不同阶段,例如install/检查/编译/部署服务器。gitlab平台会扫描.gitlab-ci.yml文件,并据此处理ci流程
  • ci流程在每次团队成员push/merge后之后触发。每当你push/merge一次,gitlab-ci都会检查项目下有没有.gitlab-ci.yml文件,如果有,它会执行你在里面编写的脚本,并完整地走一遍从intall => eslint检查=>编译 =>部署服务器的流程。
  • gitlab-ci提供了指定ci运行平台的机制,即gitlab-runner,只要在对应的平台(机器或docker)上下载并运行这个命令行软件,并输入从gitlab交互界面获取的token, 就可把当前机器和对应的gitlab-ci流程绑定,即:每次跑ci都在这个平台上进行。
  • gitlab-ci的所有流程都是可视化的,每个流程节点的状态可以在gitlab的交互界面上看到,包括执行成功或失败
  • 不同push/merge所触发的CI流程不会互相影响
  • pipeline即可被动触发也可手动触发

YML配置文件语法

YML是一种编写配置文件的语言,比JSON更为简洁和方便。

下面我们看下简单的YML文件编写:

install-job: # 注释
  tags:
    - sss
  stage: install
  script:
    - npm install
    

从上面代码中我们可以看出YML编写的一些特点:

  • 通过缩进组织层级
  • 允许通过#符号编写注释
  • YML也是由对象,数组,以及对象和数组的嵌套结构组成的全局关键字,定义阶段
常见JSON写法

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"
   }
}
需要注意的是:
  • 不再需要“{}”这种符号去区分层级边界了,但是需要考虑使用缩进
  • 可以使用注释,用#符号
  • 不涉及特殊符号时,不需要給YML中的字符串加双引号或者单引号的,当然加了也是可以的

例如:

stages:
  - build
  - test
  - deploy

常见配置关键字

  • stages
  • stage
  • script
  • tags

具体关键字说明

stages

定义在YML文件的最外层,是一个数组,用于定义一个pipeline不同的流程节点

stages: # 所有阶段
  - install
  - eslint
  - build
  - deploy

script

由运行程序执行的 Shell 脚本,以项目根目录为上下文执行,是控制CI流程的核心,即安装、编译、部署的流程都是通过script定义的shell脚本来完成。

test:
  script:
    - 'curl --request POST --header "Content-Type: application/json" "https://gitlab/api/v4/projects"'

stage

具体的某个阶段,是一个字符串,是stages数组的一个子项,表示当前的pipeline节点

  • 蓝色表示正在执行
  • 灰色表示尚未执行
  • 绿色表示执行成功
  • 红色表示执行失败
build:
  stage: build

only/except

后面跟的值是tag或者分支名的列表.

  • only的作用是指定当前Job仅仅只在某些tag或者branch上触发
  • 而except的作用是当前Job不在某些tag或者branch上触发
deploy:
  stage: deploy
  only:
  	variables:
  		- $CI_COMMIT_TAG
      - $CI_COMMIT_NAME == "prod"
    - tags
  tags:
    - k8s

tags

使用标记从项目可用的所有运行器列表中选择特定的运行器。注册运行程序时,可以指定运行程序的标记,例如ruby、postgres、development。

build:
  stage: build
  tags:
    - k8s

artifacts

将生成的资源作为pipeline运行成功的附件上传,并在gitlab交互界面上提供下载

build:
  stage: build
  script:
  - 'npm run build'
  artifacts:
    name: 'bundle'
    paths: 
      - build/

dependencies

任务依赖。指定job的前置job。添加该参数后,可以获取到前置job的artifacts。注意如果前置 job 执行失败,导致没能生成artifacts,则 job 也会直接失败。

variables

用于定义变量

image/services

可使用Docker的镜像和服务运行Job.image 是执行 CI/CD 依赖的 Docker 基础镜像。镜像中有 Node、Yarn、Dalp.

总结:
  1. stage/script/tags这三个关键字,都是作为Job的子属性来使用

新项目接入GitLab CI/CD 流程

  • 新建 GitLab 项目
  • 配置 GitLab Runner
  • .gitlab-ci.yml 文件

自动化部署的优势

  1. 提高前端的开发效率和开发测试之间的协调效率

    前端开发在提交代码之后就不用管了,ci流程会自动部署到测试或集成环境的服务器。很大程度上节约了开发的时间;同时,开发和测试人员可以共用gitlab里的pipeline界面, 测试同学能够随时把握代码部署的情况,同时还可以通过交互界面手动启动pipeline,自己去部署测试,从而节约和开发之间的沟通时间。

  2. 从更细的粒度把握代码质量

参考:

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

你可能感兴趣的:(前端,ci/cd)