# 利用 Gitlab CI/CD + Jenkins 实现自动构建,自动部署

本来只是想用 curl 去模拟触发部署静态资源的请求的。后来想到如果把这个操作交给 gitlab 操作岂不是更方便? 所以这几天折腾了一下 gitlab 的 CI/CD,读了一些 gitlab 的官方文档,进一步完善了.gitlab-ci.yml。记录这个过程如下:

# 模拟请求

利用 curl 命令行工具去模拟我们点击 开始构建 时那一时刻发起的第一个请求。

# 第一个请求

image.png 经实践,第一个请求为上面的这个请求,重要参数是 json:xxx 和 Cookie,请求结果是一个 303 重定向。

# 编写请求脚本

方便起见,首先用浏览器提供的方式,复制该请求。 image.png复制了整个请求之后,删除了一些不必要的参数之后,与提取 env, branch 这些变量之后, 得知下面的脚本

env=uat
branch=test

curl 'https://xxxx/job/tao.tao/build?delay=0sec' \
  -H 'Cookie: JSESSIONID=8EF2BD7082FB37279EE93A3B7BB3ED25' \
  --data-raw 'json={"parameter":[{"name":"PJ","value":"crm-finance-static"},{"name":"MYENV", "value":"'$env'"},{"name":"TAG","value":"'$branch'"}]}' \
  --compressed

上面的脚本是用 cookie 做用户认证的,既然是 cookie,就存在过期的可能。还好 Jenkins 提供了 token 的方法给用户。 具体看官方文档这两篇文章: https://www.jenkins.io/doc/book/system-administration/authenticating-scripted-clients/ (opens new window) https://www.jenkins.io/blog/2018/07/02/new-api-token-system/ (opens new window)

配置了 token 之后,修改之后脚本

env=uat
branch=test

curl 'https://xxxx/job/tao.tao/build?delay=0sec' \
  --user tao-tao:1169ee9c0493b27d915632c0577fdd66fd \
  --data-raw 'json={"parameter":[{"name":"PJ","value":"crm-finance-static"},{"name":"MYENV", "value":"'$env'"},{"name":"TAG","value":"'$branch'"}]}' \
  --compressed

我们直接使用了 sh 上面的脚本.sh  执行,打开 jenkins 发布平台就可以看到有任务在执行了

# 安排到 gitlab 上面

注:原来已经有了.gitlab-ci.yml 文件存在了,主要负责: 当我们 push 代码到 gitlab 仓库之后,自动执行 build 命令,并且复制到目标静态资源仓库中,之后再 push 到 gitlab 上

不熟悉 gitlab 工作流的话,可以先看,开卷有益

  1. https://docs.gitlab.com/ee/ci/introduction/ (opens new window)
  2. https://docs.gitlab.com/ce/ci/quick_start/README.html (opens new window)

增加如下代码:

deploy:
  stage: deploy
  only:
    - /^(test|pre|dev)$/
  script:
    - command -v curl >/dev/null 2>&1 || exit 1 #判断是否执行curl,否则推荐脚本
    - env="$REF_NAME" # 默认env 与 分支名一致, 特殊处理uat --》 test
    - >
      if [ "$REF_NAME" == "test" ]; then
        env="uat"
      fi
    - sh ./scripts/fetch-jenkins.sh $env $REF_NAME # 执行脚本, 带上参数

最初我是放在 after_script 中执行的,后来发现 after_script 即使脚本执行出错,gitlab 上面的 CI/CD/Pipelines 的 Job 的状态,照样是 passed 状态。 搜索得知 after_script 中是忽略失败的,如果需要支持的话,要另外安装脚本,具体可以看如下解释:https://gitlab.com/gitlab-org/gitlab-foss/-/issues/43010 (opens new window),所以我后面把它放在了 script 中,这样脚本出错的话,Job 的状态也是 failed 的状态(Job 失败的话,gitlab 还给我们发了邮件)


另外,curl 只是模拟构建请求,但是我们如何判断请求成功还是失败的?前面我们说构建请求是返回 303 重定向的, 没有 response 内容回来,据此我们就可以判断,请求成功还是失败了,如果有请求结果的话,脚本就 exit 1

if [ "$RES" ]; then { echo 'failed!'; exit 1;  } fi

.gitlab-ci.yml  与 fetch-jenkins.sh  代码附件: .gitlab-ci.yml (opens new window) fetch-jenkins.sh (opens new window)

# 忽略.gitlab-ci.yml 的作用

如果我们有一个这样的需要,在某一次 push,我不需要 gitlab 执行构建任务,或者我们觉得 gitlab 构建任务 pengding 太久, 或者 running 太慢。 如何解决这个痛点呢?

这样,我们如果控制 push 代码的时候,携带信息通知 gitlab 服务器,达到我们想要的结果。

很幸运,Gitlab CI/CD 是提供这个服务的,只不过有版本限制, image.png 得知,我们的 gitlab runner 版本是image.png是支持 ci.skip。

携带 -o ci.skip 之后 再 Pipelines 中就可以看到 ,如下图所示:跳过 jobimage.png

# 本地执行 CI/CD 脚本

如果觉得 gitlab 构建速度太慢,结合我之前写的构建脚本,同样也可以实现自动构建,自动部署。

大概脚本如下:

#!/usr/bin/env bash
set -euo pipefail
branch=$1
curPath=`pwd`
targetPath="./build" # 打包静态资源路径配置, 为了统一推荐clone在源码根目录下的build文件夹(.gitignore 已忽略build)
commitID=`git rev-parse --short HEAD` # get last commit SHA
subModule=finance
curBranch=`git symbolic-ref --short -q HEAD` # get current branch

# 首先判断是否在目标分支build
if [ "$curBranch" != "$branch" ]; then
    echo -------------------------------------
    echo -e "\033[41;37m please checkout $branch before building \033[0m"
    echo -------------------------------------
    exit 1
fi

cd "$targetPath"
# 获取分支名称
targetBranch=`git symbolic-ref --short -q HEAD`
#  判断是否在目标分支,不在的话checkout
if [ "$targetBranch" != "$branch" ]; then
    git checkout "$branch"
fi

git pull
rm -rf "$targetPath/$subModule/"
cp -r "$curPath/dist/$subModule/" "./"


message="deploy based on $branch from $commitID"

# set +e
git add .
git commit -m "$message"
git push -u origin

cd -

# fetch jenkins interface
case $branch in
  dev  ) env="dev"
      ;;
  test ) env="uat"
      ;;
  pre )  env="pre"
      ;;
  master ) echo -e "\033[41;37m not support master \033[0m" && exit 0
      ;;
  *    ) echo -------------------------------------
         echo -e "\033[41;37m branch($branch) error before fetch jenkins \033[0m"
         echo -------------------------------------
         exit 1
esac

sh ./scripts/fetch-jenkins.sh $env $branch # 执行触发jenkins请求脚本

附件如下:

然后 package.json 在配置如下 image.png

直接执行 yarn deploy:dev 就帮助我们构建,push 到静态自然仓库,触发 jenkins 请求,部署到了 dev 了

最后,CI/CD 能有很多方式实现,有待大家挖掘, 这个也算是根据实际的项目情况,打通了 Jenkins,欢迎大家多多交流。