所需环境

  • Gitlab (可以参考之前的 《DevOps 之快速搭建 Gitlab 服务》
  • 运行 Gitlab Runner 的 Server (可以参考之前的《DevOps 之注册 Gitlab Runner》)
  • 用于部署 Vue 项目的 Server (可以是运行 Gitlab Runner 的服务器, 如果不是,则需要将运行 Gitlab Runner 的服务器的 Public key 添加到用于部署 Vue 的服务器上)
  • Gitlab Runner 以 Docker 的方式运行

编写 CI 配置文件

Cache 和 Artifacts

很多人对与 Cache 和 Artifacts 这两个的作用不是很清楚,其实官方文档中也又一定的说明。 Cache 适用于在多个阶段中共享的依赖文件,例如 Vue 项目依赖的 NPM 包,也就是 node_modules 目录,而 Artifacts 则是在构建或测试中产生的数据,这类数据往往不想被覆盖,甚至需要上传至 Gitlab 服务器。

流水线中的阶段

因为 Vue SPA 的特性,所以并不依赖其他服务,我们只需要安装一些依赖,然后进行打包,最终部署到预览和线上环境即可。根据上述需求,我们将整个 Pipeline 设置为两个 Stage,效果如下:

stages:
  - build   # 安装依赖和构建项目
  - deploy  # 部署到预览和线上环境

每个阶段的任务

构建阶段的任务

build:
  image: node:latest # 指定镜像
  stage: build # 指定所属的阶段
  tags:
    - sonitus #指定需要在那个 Runner 上运行该任务
  only: # 定义监听分支,当分支发生变化则触发 CI
    refs:
      - master
      - develop
      - tags
  script: # 执行的脚本
    - yarn install
    - yarn build
  artifacts: # 定义需要上传的文件或目录
    name: "$CI_COMMIT_REF_SLUG"
    when: on_success # 定义只有当任务成功时才上传
    expire_in: 1 week # 定义文件过期时间,过期后将自动删除
    paths: # 定义需要打包上传的文件或目录
      - dist/

部署阶段的任务

因为我们有预览环境和线上环境,所以在部署阶段我们有两个任务,预览环境与 build stage 的触发条件一致,也就是 master、develop 和 tags 发生变化时都部署到预览服务器。而线上环境的部署则只监听 tags 的变化,并且需要开发人员或运维人员在 Gitlab 的项目页面手动触发部署任务。

deploy:preview:
  image: alpine:latest # 指定镜像
  stage: deploy
  tags:
    - sonitus
  when: on_success
  script:
    - apk add --no-cache rsync openssh # 安装 rsync 和 openssh
    - mkdir -p ~/.ssh
    - echo "$PREVIEW_SSH_PRIVATE_KEY" >> ~/.ssh/id_rsa # 将 Gitlab 里设置的的私钥环境变量输出到 ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - rsync -rav -e "ssh -p $PREVIEW_SERVER_PORT -o StrictHostKeyChecking=no" --delete dist/ "$PREVIEW_SERVER_USER"@"$PREVIEW_SERVER":"$PREVIEW_PROJECT_PATH" # 将构建的 dist 部署到服务器上
  only:
    refs:
      - master
      - develop
      - tags
  dependencies: # 定义依赖,当 build 任务完成后才能执行
    - build
  environment: # 定义环境
    name: preview
    url: https://vue.betterde.com # 定义访问的 URL

deploy:production:
  image: alpine:latest
  stage: deploy
  tags:
    - sonitus
  script:
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$PRODUCTION_SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - rsync -rav -e "ssh -p $PRODUCTION_SERVER_PORT -o StrictHostKeyChecking=no" --delete dist/ "$PRODUCTION_SERVER_USER"@"$PRODUCTION_SERVER":"$PRODUCTION_PROJECT_PATH"
  when: manual # 定义为手动触发
  only:
    refs:
      - tags # 只有打了 tag 才会展示该 Job
  dependencies:
    - build
  environment:
    name: production
    url: https://vue.betterde.com

这里需要注意的是,部署阶段中涉及很多环境变量(这些环境变量的名称可以自己定义),这些环境变量需要在 Gitlab 中进行设置。访问路径是:Project > Settings > CI/CD > Variables。

Project > Settings > CI/CD > Variables

还有就是需要注意项目是否有可用的 Runner, 同样的也是访问: Project > Settings > CI/CD > Runners,查看指定 tag 的 Runner 是否可用。

Project > Settings > CI/CD > Runners

完整的 CI 配置文件

stages:
  - build
  - deploy

variables:
  GIT_STRATEGY: fetch

cache:
  paths:
    - node_modules/

build:
  image: node:latest
  stage: build
  tags:
    - sonitus
  only:
    refs:
      - master
      - develop
      - tags
  script:
    - yarn install
    - yarn build
  artifacts:
    name: "$CI_COMMIT_REF_SLUG"
    when: on_success
    expire_in: 1 week
    paths:
      - dist/

deploy:preview:
  image: alpine:latest
  stage: deploy
  tags:
    - sonitus
  when: on_success
  script:
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$PREVIEW_SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - rsync -rav -e "ssh -p $PREVIEW_SERVER_PORT -o StrictHostKeyChecking=no" --delete dist/ "$PREVIEW_SERVER_USER"@"$PREVIEW_SERVER":"$PREVIEW_PROJECT_PATH"
  only:
    refs:
      - master
      - develop
      - tags
  dependencies:
    - build
  environment:
    name: preview
    url: https://vue.betterde.com

deploy:production:
  image: alpine:latest
  stage: deploy
  tags:
    - sonitus
  script:
    - apk add --no-cache rsync openssh
    - mkdir -p ~/.ssh
    - echo "$PRODUCTION_SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
    - chmod 600 ~/.ssh/id_dsa
    - rsync -rav -e "ssh -p $PRODUCTION_SERVER_PORT -o StrictHostKeyChecking=no" --delete dist/ "$PRODUCTION_SERVER_USER"@"$PRODUCTION_SERVER":"$PRODUCTION_PROJECT_PATH"
  when: manual
  only:
    refs:
      - tags
  dependencies:
    - build
  environment:
    name: production
    url: https://vue.betterde.com

总结

接下来,我们就可以测试整个 CI 流程了,当我们 push、merge 或打 tag 发布 release 时将触发 CI,如上面的配置那样,如果你只是对 master 和 develop 分支做操作。那么在后台的 Pipelines 中看到两个 stages 和两个 jobs:

当 PUSH 到 master 分支时的 Pipelines 中的 Jobs

当我们为项目打了 v1.0.1 的 tag 后并发布了 release,则此时的 Pipeline 的 Jobs 如下:

打了 tag 后的 Jobs

可以看到 deploy:procuction 这个 Job 出现了,但是并没有触发,此时需要我们人工的点击后面的 Run 按钮来触发这个 Job,从而实现部署到生成环境中。在手动触发前可以点击这个 Job (不是后面的按钮)进入 Job 的详情页,设置临时环境变量,然后点击下方的 Trigger this manual action 来触发。

到这里整个关于 Gitlab CI 构建部署 Vue 的项目就算完成了。希望大家也能通过 Gitlab CI 来替代人工,从而腾出更多时间,去做更多有价值的事情。

I hope this is helpful, Happy hacking…