Gitlab CI&CD 在前端项目自动化构建部署中的实践

引言

现在大部分的公司都搭建了自己的Gitlab,除了Git的代码管理能力,Gitlab的CI&CD在项目的持续集成和部署上也尽力提高大家的工作效率。下面用我们项目的例子为大家引荐一下这套工具带来的便利。

Gitlab CI&CD是什么
Gitlab CI&CD 在前端项目自动化构建部署中的实践
如上官方图示,可以理解为Gitlab给开发者提供了一项功能,在代码提交后自动触发一段开发者自定义的脚本,以此来完成诸如但不限于构建部署的工作。

为什么我们需要使用

  1. 项目业务较多,多个业务并行联调或测试(不要问我分支怎么管理的,后面说);
  2. 不断有新人进入;
  3. 测试机器时常有被更换的风险;
  4. 项目依赖包时常会更新,每个人环境的依赖包小版本可能不一致。

因此我们迫切的需要一个新人低成本或零成本的、快速自动化的构建部署方案。

解决方案

  1. 为环境指定不同的分支,如dev1 代表联调环境1,test2 代表测试环境2,… ,testN 代表测试环境N。如下图,各分支与环境的关系
    Gitlab CI&CD 在前端项目自动化构建部署中的实践

  2. 利用Gitlab CI&CD工具执行自动化构建,并根据分支部署到不同机器,如上图,发布到个环境前都经过了CI阶段的自动化构建等操作,线下测试和联调还可以在CD阶段自动部署到对应服务器

执行步骤

  1. 在仓库里面配置.gitlab-ci.yml
  2. 在可以访问git仓库的服务器部署Runner
  3. 在git仓库网页上配置对应的Runner

项目配置

配置文件 .gitlab-ci.yml
在项目的根目录下创建文件.gitlab-ci.yml

Keyword Required Description
script yes CI&CD过程需要执行的shell脚本
stage no 一个job流程,默认test
variables no 定义变量
only no 指定当前job适用的git refs(分支、Tag)列表
except no 与only相反
tags no 通过标签管理或匹配runner
allow_failure no 指定当前job是否容错,正常job失败会跳过后续job流程
before_script no 在当前job执行前执行的shell脚本
after_script no 在当前job执行后执行的shell脚本
when no 依赖的上一个job执行什么状态后执行当前job, on_success on_failure always manual 默认on_success
dependencies no 指定依赖的job列表,默认顺序执行

查看其他可配置属性

# 执行job的阶段 按顺序串行执行
stages:
  - build
  - cleanup
  - deploy

# 自定义阶段build的job流程
build: # 自定义名字
  stage: build # 指定这阶段操作的名称
  only: # 指定那些分支会进入该处理流程
    - master # 正式环境
    - pre # 预发环境
    - testN # 测试环境 test1 test2 ... testN
    - devN # 联调环境 dev1 dev2 ... devN
  variables:
    VERSION: 1.0.10 # 除了后面会说到的私密变量 还可以在这里定义变量
  before_script:
    # 一些特殊情况需要SSH key的场景,该部分见下文
    # - ...
    # 定义变量 如NODE环境变量
    - NODE_ENV=`if [[ ${CI_COMMIT_REF_NAME:0:3} = "dev" || ${CI_COMMIT_REF_NAME:0:4} = "test" ]]; then echo "development"; else echo "production"; fi`;
  script:
    # 为node modules做缓存, 有缓存用缓存,没有则你npm install并添加缓存
    - PACKAGE_HASH=$(md5sum package.json | awk '{print $1}');
    - mkdir -p ~/builds/cache/node_modules # 使用docker模式时需要配置volume 保证缓存起作用 在后面runner部分会提到。
    - NPM_CACHE=~/builds/cache/node_modules/${PACKAGE_HASH}.tar
    - if [ -f $NPM_CACHE ];
      then
        echo "Use Cache";
        tar xf $NPM_CACHE;
      else
        npm install;
        tar cf - ./node_modules > $NPM_CACHE;
      fi
    # npm build
    - echo "NODE_ENV=$NODE_ENV node build/build.js"
    - NODE_ENV=$NODE_ENV node build/build.js
    # upload to CDN
    # - ...
    # docker build
    - echo `docker build -t "$CI_PIPELINE_ID" . | awk -F "Successfully built " '{print $2}'`
    # docker push
    - if [ $NODE_ENV = "development" ]; # 如果需要部署的server的runner在同一个机器则可不必push到仓库
      then
        docker login dev.hub.xxx.com -u$USERNAME -p$PASSWORD;
        docker tag $CI_PIPELINE_ID dev.hub.xxx.com/namespace/webapp:$CI_COMMIT_REF_NAME;
        docker push dev.hub.xxx.com/namespace/webapp:$CI_COMMIT_REF_NAME;
        docker rmi dev.hub.xxx.com/namespace/webapp:$CI_COMMIT_REF_NAME;
        echo "--------------------------------------------------------------------------";
        echo "dev.hub.xxx.com/namespace/webapp:$CI_COMMIT_REF_NAME";
      else
        # 参考上面then中脚本
        "--------------------------------------------------------------------------";
        echo "hub.prd.xxx.com/namespace/webapp:$DATE.$CI_BUILD_ID";
      fi

# 开发和测试机部署
clean_testN:
  stage: cleanup
  only:
    - testN
  tags:
    - dc2fe-deploy-testN
  script:
    - docker stop webapp
    - docker rm webapp
  allow_failure: true

deploy_testN:
  stage: deploy
  only:
    - testN
  tags:
    - dc2fe-deploy-testN
  script:
    # - ssh [email protected] "docker stop webapp; docker rm webapp; docker run --name webapp -d -p 8000:8000 dev.hub.xxx.com/namespace/webapp-testN:latest"
    # 或者
    - docker pull dev.hub.xxx.com/namespace/webapp:testN
    - docker run --name webapp -d -p 8000:8000 dev.hub.xxx.com/namespace/webapp:testN

# clean_dev: # dev或其他环境部署配置与上面test环境配置类似
# deploy_dev:

如果

  • 你的CI Runner的执行环境没有权限访问你们公司的Gitlab仓库(一般使用docker模式的Runner或者项目底下有子模块submodule,且需要在Runner中构建的时候checkout)
  • 当前项目构建完后需要部署到其他服务器,或者需要执行sshrsync等需要认证命令时

你需要

在本文中你可以认为ssh-agent是一个用来在ssh会话过程中管理你的ssh私钥,并在git仓库或服务器需要ssh key认证的时候自动提供与对应公钥匹配认证的工具

before-script:
  - eval $(ssh-agent -s)
  # 清除一些系统中复制出现的换行符\r,并重定向到/dev/null防止泄露
  - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
  # 创建~/.ssh目录,并配置权限(非root运行的runner)
  - mkdir -p ~/.ssh
  - chmod 700 ~/.ssh

除了自己配置的变量,Runner也提供了一些 预置变量

shell模式的Runner需要添加

  - ssh-keyscan Runner宿主机需要访问的服务器hostname(git。xxx.com或IP) >> ~/.ssh/known_hosts

docker模式的Runner可直接关闭ssh登录目标host key检查

  - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'

CI Runner

安装
Runner的安装比较简单,根据官方流程即可, 以Linux x86-64为例

 # 下载gitlab-runner并安装
 sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
 
# 2. 授执行权
 sudo chmod +x /usr/local/bin/gitlab-runner

# 创建GitLab CI用户:
 sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash

# 安装并启动:
 sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
 sudo gitlab-runner start

配置
注册项目
Gitlab CI&CD 在前端项目自动化构建部署中的实践

  1. 配置项目ci的仓库地址 如下图灰色mask部分2
  2. 配置项目唯一标识Token 如下图灰色mask部分3
  3. 给当前Runner一个描述,或者命名
  4. 配置当前Runner的Tag, 可以多个,tag可以用来管理和关联项目和Runner,以实现部署到不同服务器等
    Gitlab CI&CD 在前端项目自动化构建部署中的实践
  5. Runner的其他属性配置, 也可以在界面配置如下图
    Gitlab CI&CD 在前端项目自动化构建部署中的实践
  6. 配置当前Runner的模式,

成功
Gitlab CI&CD 在前端项目自动化构建部署中的实践
如图,配置成功后当你提交代码到对应配置了CI&CD stage的分支,Gitlab就会自动触发执行脚本,当然如图所示,你也可以直接在界面上重试或新建pipelines

一次提交触发一次CI&CD即执行一次脚本对应一个pipeline;一个pipeline对应stages下的所有job;一个stage对应一个job;一个job可以允许失败,比如我们的例子中,每次清除就得docker容器的时候可能失败,因为新机器上没有对应的容器或者其他一些不影响主流程的操作可以添加容错配置。

结语

  1. 除了给Gitlab仓库配置CI&CD,同时他也支持其他仓库如Github等;
  2. Gitlab也定义了一下API可以结合其他工具来执行CI&CD任务;
  3. 如果使用gitlab>=v11的版本还可以根据需要配置Auto DevOps

这是我们使用的例子,如有其他需求和问题可以评论讨论或回复不及时时请查看https://docs.gitlab.com/ee/ci/README.html#advanced-use

本文是滴滴云开源工具教程系列文章的一篇。