搭建GitLab的cicd流水线

发布时间 2023-11-30 14:40:48作者: 柯基与佩奇

大致内容如下

  1. 通过部署一个简单的项目到 gitlab pages 初步了解 gitlab CI/CD
  2. 了解 gitlab CI/CD 基础概念、运行机制等
  3. 使用 gitlab 自带 runner 进行自动化部署、使用 ssh 命令操作部署远程服务器
  4. 在自己服务器安装 gitlab runner 进行自动化部署
  5. 两种 runner 部署耗时对比
gitlab runner 类型 部署方式(自动触发/手动一键部署等) 环境
gitlab 共享 runner 部署 vitepress 项目到 gitlab pages ---
gitlab 共享 runner 部署 vitepress 静态站点到 oss 测试/正式
gitlab 共享 runner 部署 vue3+vite 项目到腾讯云 测试/正式
gitlab 共享 runner 部署 koa 接口服务器到腾讯云 测试/正式
阿里云 2c4g 服务器安装 runner 部署 vitepress 静态站点到 oss 测试/正式
阿里云 2c4g 服务器安装 runner 部署 vue3+vite 项目到腾讯云 测试/正式
阿里云 2c4g 服务器安装 runner 部署 vue3+vite 项目到当前 runner 所在机器 测试/正式
阿里云 2c4g 服务器安装 runner 部署 koa 接口服务器到腾讯云 测试/正式

部署 vitepress 项目到 gitlab pages

先通过一个简单、容易上手的实践来了解 gitlab 自动化部署大致流程

1-1-vitepress-gitlab-pages.png

在 VitePress 官网中有一个 部署 vitepress 项目到 gitlab pages 的教程,比较简单,分两步

  • 1、修改 docs/.vitepress/config.ts 配置文件,将 vitepress 构建后的生成文件放到项目根目录 public 文件夹中(gitlab pages 有这个要求)。相关 demo vitepress-new
  • 2、在项目根目录新建 .gitlab-ci.yml 写入如下内容
image: node:16
pages:
  cache:
    paths:
      - node_modules/
  script:
    - npm install
    - npm run docs:build
  artifacts: # 制品 /ˈɑːtɪfækt/
    paths:
      - public
  only:
    - main

Gitlab pages 仓库配置问题

理论上,经过上面两个步骤后,只要修改代码推送到 gitlab 远程仓库,就会触发 gitlab CICD 自动部署。但实际操作中,对于新创建的 gitlab 仓库,需要在仓库 - 设置中开启 gitlab pages,不然就算写好了 .gitlab-ci.yml 内容,也无法触发 gitlab pages 自动化部署。

如下图,在 Settings - Pages 设置中,会引导你填写内容,自动生成 .gitlab-ci.yml。这里 build image 填 node:16,勾选 build 输出目录为 public,下一步直到完成。

1-2-gitlab-pages-settings.png

设置完成后之前填写的 .gitlab-ci.yml 内容可能会被覆盖,需要修改为上面提到过的 vitepress 官网提供的部署配置文件。提交后,会触发自动化部署流程。如下图

1-3-gitlab-pages-cicd.png

部署成功后,可以通过 https://<username>.gitlab.io/<repository>/ 来访问部署后的内容,比如 username 是 zuoxiaobai, 项目仓库为 vitepress-new,即可通过 zuoxiaobai.gitlab.io/vitepress-n… 来访问部署到 gitlab pages 后的内容,如下图

1-4-gitlab-pages-effect.png

修改代码测试自动化部署更新

为了测试提交代码自动化部署,这里提交一个文案改动,push 到远程

1-5-gitalb-pages-update-code.png

可以看到,如下图 Build - Pipelines 流水线中自动触发最新代码的 CI/CD 流程

1-6-gitlab-pages-cicd-running.png

43s 后部署完成,再次访问页面,就是最新的内容了,如下图

1-7-gitlab-pages-effect-diff.png

其他注意点

1、vitepress 项目部署到 github pages 时,项目结构要规范,内容根据官网文档使用 docs 目录包裹,不要省去,不然 public 目录会冲突

2、针对 gitlab pages 部署到的页面,如果项目仓库是私有的需要登录才能访问,因此一般这种页面如果需要所有人能看到,需要将仓库设置为 public

Gitlab 基础概念

上面初步体验了 gitlab 的自动化部署流程,为了更好的进行后续的内容,这里建议大家先把 Gitlab-ci:从零开始的前端自动化部署 - 知乎 这篇文章大致看一遍,对 gitlab 基础概念有一个大致的了解。

下面概括内容就是来自该文章,如果你对以下概念比较熟悉,可以跳过 Gitlab 基础概念 这部分内容

  • gitlab CI/CD 运行机制、.gitlab-ci.yml 配置文件
  • Pipelines、Stage、Job、Artifacts
  • GitLab runners(Shared runners、Project runners、Group runners)、Executors

Gitlab CI/CD 运行机制

当 Gitlab 仓库出现 push/merge 操作时,会检测当前项目根目录是否有 .gitlab-ci.yml 文件,如果有就执行该配置文件中的 CICD 自动化部署脚本。(这点和 Github Actions 有点类似,只是 Github 检测路径是 .github/workflows/*.yml )

.gitlab-ci.yml 配置文件 用于指定 CI/CD 构建部署逻辑,比如 npm install、build、ssh 部署等。

这些步骤像流水线操作一样,一般会把这个过程叫做 Pipelines(流水线)

1-8-gitalb-base-pipelines.png

每一个流水线包含多个 Stage(阶段/步骤) ,每个阶段/步骤可以有 1 个或多个 Job(任务)

1-9-gitalb-base-stage-job.png

上面图中对应 .gitlab-ci.yml 配置如下

1-10-gitlab-base-yml-config.png

Runners 与 Executors

Runners 可以简单理解为运行 .gitlab-ci.yml 部署脚本所使用的机器,参考 What is GitLab Runner?,一般分为两种

  • Gitlab 自有的 Shared runners(默认),可免费使用,会有使用时长限制,构建部署过程运行在 Gitlab 提供的云服务器上。 可以用于所有 group 和 project,每个 CI/CD Job 都运行在一个隔离、独立的虚拟机上。
  • 自定义 runner(Project runners、Group runners) ,在自己的服务器上安装 gitlab runner 程序,指定用这个 runner 来执行 .gitlab-ci.yml 部署构建流程。

如下图,可以在仓库的 Settings - CI/CD - Runners 中进行设置,关联自定义 runner 服务器

1-11-gitlab-base-runners.png

一般在自己的服务器上安装 gitlab runner,会让你选择一个 executors (执行器/执行程序),用于指定这个 runner 中每个 Job 运行的环境,如下图,有多种选择

1-12-gitlab-runner-executor.png

一般选择 shell 会简单一点,docker 也不错,可能对服务器内存要求高点,更多细节、区别参见官方文档 Runner executors | GitLab

Artifacts 制品

.gitlab-ci.yml 配置中的 artifacts 用于指定制品(也就是 npm run build 构建生成的文件)所在路径,在 Pipelines 下面的菜单中有对应的制品菜单,可以下载/查看历史制品文件。

# .gitlab-ci.yml
build-job:
  stage: build
  script:
    - npm run build
  artifacts:  # 制品目录 /ˈɑːtɪfækt/
    paths:
      - dist
​
deploy-job:
  stage: deploy
  script:
    # - ls; pwd; # 查看运行路径
    - ssh root@$CUSTOM_IP "rm -rf /root/demo.zuo11.com"
    - scp -r ./dist root@$CUSTOM_IP:/root/demo.zuo11.com

不同用户不同的菜单/页面

另外不同的用户、权限看到的 gitlab 页面可能不一样,如下图,公共仓库中所有者、未登录访客菜单会有一些区别,部署相关的一个是 Build - Pipelines ,一个是 CI/CD - Pipelines

1-13-gitlab-base-ui-diff.png

使用 gitlab 自带 runner 进行部署

下面依次用三个项目使用 gitlab 自带 runner 来进行多环境 CICD 自动化部署

  • 部署 vitepress 静态站点到阿里云 oss(测试/正式)
  • 部署 vue3+vite 前端项目到腾讯云服务器(测试/正式)
  • 部署 koa+ mongodb 接口服务到腾讯云服务器(测试/正式)

部署 vitepress 静态站点到 oss

使用 blog - gitlab vitepress 项目用来进行测试,在项目根目录添加 .gitlab-ci.yml 文件,内容如下,分三个阶段

  1. npm install
  2. npm run build
  3. 安装阿里云 OSS 命令行工具 ossutil64、配置秘钥、部署 .vitepress/dist 到 OSS 指定 bucket
image: node:16

stages:
  - install
  - build
  - deploy

cache: # 缓存
  paths:
    - node_modules
    - build

install-job:
  stage: install
  script:
    - npm install

build-job:
  stage: build
  script:
    - npm run build
  artifacts: # 制品目录 /ˈɑːtɪfækt/
    paths:
      - ./.vitepress/dist

deploy-job:
  stage: deploy
  script:
    - ls
    - pwd
    # 安装并配置 oss,参考 https://www.mmfei.com/2021/05/通过gitlab的ci自动部署前端项目到阿里云的oss/
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com

其中阿里云 oss 命令行部署工具 ossutil64 需要配置 3 个敏感信息,怎么获取这些值?参考文档 配置 ossutil - 阿里云

  • -e endpoint, 设置 Bucket 所在地域的域名信息 OSS_END_POINT
  • -i accessKeyID, 访问密钥的一部分,用于标识用户身份,以对命令请求进行身份验证。OSS_ACCESS_KEY_ID
  • -k accessKeySecret, 访问 OSS 使用的访问凭证。OSS_ACCESS_KEY_SECRET

可以在 gitlab 对应仓库 Settings - CI/CD - Variables 位置设置这 3 个变量的值

1-14-gitlab-oss-set-variables.png

设置完成后,提交 .gitlab-ci.yml 代码就会触发自动化部署,在仓库目录下的 Build - Pipelines 中可以看到,如下图

1-15-gitlab-oss-pipelines.png

部署的目标 oss bucket 关联了 test.zuo11.com,在部署完成后,访问 test.zuo11.com 就能看到最新的内容,如下图

1-16-gitlab-oss-success.png

手动触发一键部署

上面的 .gitlab-ci.yml 配置在每次提交 push 到远程都会触发触发自动化部署。但有些提交比较频繁的场景,为了不浪费部署服务器性能,需要设置为手动触发,可以使用 when: manual 让某个 Job 只有手动点击才能触发,yaml 配置参数详情可以参考 .gitlab-ci.yml keyword reference - GitLab

install-job:
  stage: install
  script:
    - npm install
  when: manual

想的是把 npm install 安装依赖这个 Job 设置为手动触发,就可以阻止后续的执行。但提交后发现,居然只跳过这个 Job,下面的两个步骤依旧正常执行,如下图

1-17-gitlab-oss-manual.png

为了手动部署时可以一键部署,把安装依赖、build 两个 stage 合并到 deploy stage,只保留一个 stage,配置如下

image: node:16

stages:
  - deploy

cache: # 缓存
  paths:
    - node_modules

deploy-job:
  stage: deploy
  script:
    - ls
    - pwd
    - npm install
    - npm run build
    # 安装并配置 oss
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com
  when: manual
  artifacts:
    paths:
      - ./.vitepress/dist

提交后,状态如下,点击 Stages 状态图标 - Paly,就可以一键部署了,如下图

1-18-oss-one-keypress-deploy.png

修改标题后,点击手动部署,成功后再访问 test.zuo11.com 即可看到效果

1-19-one-update-deploy.png

多环境部署配置 only

在 gitlab 中,多环境可以使用 only 或者配置 environments 来实现。

先来看使用 only 指定分支,不同分支部署到不同 oss bucket

环境 oss bucket 分支 域名
正式环境 test-zuo11-com main test.zuo11.com
测试环境 test-zuo11-com-dev v1.0.0 test-dev.zuo11.com

对应的 .gitlab-ci.yml 配置如下

image: node:16

stages:
  - deploy-prod
  - deploy-dev

cache: # 缓存
  paths:
    - node_modules

deploy-job-prod:
  stage: deploy-prod
  script:
    - npm install
    - npm run build
    # 安装并配置 oss
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com
  when: manual
  only:
    - main
  artifacts:
    paths:
      - ./.vitepress/dist

deploy-job-dev:
  stage: deploy-dev
  script:
    - npm install
    - npm run build
    # 安装并配置 oss
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com-dev
  when: manual
  only:
    - v1.0.0
  artifacts:
    paths:
      - ./.vitepress/dist

这里有一个坑,就是 gitlab 非 main 分支读取不到 cicd 变量?需要看对应的变量是否勾选了 Protected,如果是,需要修改 - 取消勾选。

相关 Pipelines 流水线如下图,only 设置的分支,它的 stage 只会出现在对应的分支。修改代码提交后,点击 Statgs 图标 - Play 即可一键部署或重新部署。

1-20-oss-mutiple-ci.png

部署完成后,看测试环境 test-dev.zuo11.com 是否可以正常访问,如下图

1-21-oss-mutiple-env-1.png

多环境部署配置 environments

上面用 only 来控制 Job 仅在指定分支运行,gitlab 还有一个专门的 environments 来管理多环境,如下图

1-22-mutiple-env-environments.png

创建环境需要一个 name、url,对应环境名称、部署后的链接,配置如下

deploy-job-prod:
  stage: deploy-prod
  # ...
  environment:
    name: prod
    url: http://test.zuo11.com

deploy-job-dev:
  stage: deploy-dev
  # ...
  environment:
    name: test
    url: http://test-dev.zuo11.com

设置好环境、.gitlab-ci.yml 后,页面如下,点击 open 可以跳转到对应环境的 url

1-23-mutiple-environments-ui.png

完整配置如下

image: node:16

stages:
  - deploy-prod
  - deploy-dev

cache: # 缓存
  paths:
    - node_modules

deploy-job-prod:
  stage: deploy-prod
  script:
    - npm install
    - npm run build
    # 安装并配置 oss
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com
  when: manual
  environment:
    name: prod
    url: http://test.zuo11.com
  artifacts:
    paths:
      - ./.vitepress/dist

deploy-job-dev:
  stage: deploy-dev
  script:
    - npm install
    - npm run build
    # 安装并配置 oss
    - wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
    - chmod 755 /usr/bin/ossutil64
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com-dev
  when: manual
  environment:
    name: test
    url: http://test-dev.zuo11.com
  artifacts:
    paths:
      - ./.vitepress/dist

提交后,Pipelines 如下图,上面的配置中没有用 only 限制版本,且为手动,点击不同的 stage 图标可以一键部署到不同的环境。如果你比较细心,你可能会发现不使用 environments 也可以达到这种效果,这里使用 evironments 环境配置只是做了一个分类。

1-24-multi-env-deploy.png

使用 ssh 命令操作部署远程服务器

在将项目部署到服务器之前,有必要先来看看怎么使用 ssh 命令操作服务器,一般分为两种

  1. 使用 ssh 在远程服务器上执行命令
# 在 ip 为 47.107.49.197 的服务器上执行 "pwd;git pull" 等命令
ssh root@47.107.49.197 "pwd;git pull;npm install;npm run build;"
  1. 使用 scp 将本地文件部署到服务器(scp 可以简单理解为 cp + ssh 的组合)
# 将当前目录下的 dist 文件内容部署到服务器的 /root/demo.zuo11.com 目录
scp -r ./dist/* root@47.107.49.197:/root/demo.zuo11.com)

上面操作命令很简单,但相对麻烦的是连接远程服务器的鉴权问题,在上一篇介绍 Github Actions 部署时,有提到使用 ssh 私钥方式连接服务器并进行部署。这里再深入一点,通过纯 Linux 命令操作来理解 ssh 鉴权,一般鉴权分为两种

  • ssh 密码登录
  • ssh 私钥登录(相对更安全,但稍微麻烦一点)

ssh 密码登录

ssh 密码登录,只需要有服务器 ssh 登录的密码即可(一般可以在云服务器管理页面进行设置)

1-25-ssh-password.png

如图,由于 ssh 命令在执行时,需要人工操作输入密码,不适合自动化操作,因此一般会借助 sshpass 来自动填充密码,linux 系统不自带 sshpass,需要安装(另外 windows 不支持 sshpass)

# CenterOS 安装 sshpass
yum install sshpass -y # 如果是 Ubuntu 使用 sudo apt-get install sshpass

新服务器第一次如果不进行下面这一步,后面的 sshpass 命令操作服务器可能不会有任何效果,加入参数 -o StrictHostKeyChecking=no 表示自动信任主机

# 密码 123456 记得替换成自己的
sshpass -p 123456 ssh root@47.107.49.197 -o StrictHostKeyChecking=no

后面就可以愉快的操作服务器了,以下命令在阿里云 A 服务器上操作腾讯云 B 服务器,实测运行正常

sshpass -p 123456 ssh root@47.107.49.197 "touch 3.txt"
sshpass -p 123456 scp -r ./dist/* root@47.107.49.197:/root/demo.zuo11.com

ssh 私钥登录

假设用电脑 A 通过 ssh 登录操作服务器 B,需要两步操作

  1. 查看电脑 A 是否已经生成过 ssh 公钥/私钥对(看电脑中是否有 ~/.ssh/ 目录是否有 id_rsaid_rsa.pub 这两个文件),如果没有使用 ssh-keygen 命令生成。
  2. 复制步骤 1 中生成的 ssh 公钥内容(~/.ssh/id_rsa.pub),登录到 B 服务器执行 echo "复制的公钥内容" >> ~/.ssh/authorized_keys,将公钥内容追加到 ~/.ssh/authorized_keys 文件末尾

1-26-ssh-key.png

这样就可以直接使用 ssh/scp 操作服务器了

ssh root@$CUSTOM_IP "rm -rf /root/demo.zuo11.com"
scp -r ./dist root@$CUSTOM_IP:/root/demo.zuo11.com

部署 vue3+vite 项目到腾讯云

以配置中心前端代码 zuo-config-fe 为例,将这个 vue3+vite 项目部署到腾讯云服务器,这里使用 sshpass 密码登录方式操作,需要在仓库的 Settings- CI/CD - Variables 中设置了三个变量

变量名
PASSWORD 目标服务器 ssh 登录密码
CUSTOM_USERNAME 服务器用户名,用的是 root
CUSTOM_IP 服务器 IP

具体 .gitlab-ci.yml 配置如下

image: node:16

stages:
  - build
  - deploy

cache: # 缓存
  paths:
    - node_modules

build-job:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist

deploy-job:
  stage: deploy
  image: ringcentral/sshpass:latest
  script:
    - sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no -r ./dist/* $CUSTOM_USERNAME@$CUSTOM_IP:/root/demo.zuo11.com

由于 gitlab 自带的 shared runners 默认运行环境是 docker,上面会用到两个镜像,一个是 node 环境镜像 node:16,一个是 sshpass 镜像 ringcentral/sshpass:latest,因此把 build 和 deploy 拆成了两个 stage,不然就不支持 sshpass 命令。

提交后,会触发自动化部署,访问 demo.zuo11.com 即可看到最新内容

1-27-txy-vue3-vite.png

多环境配置

上面部署 vue3 项目到腾讯云服务器,具体操作是将 gitlab shared runners 中构建生成 dist,通过 scp 命令远程部署到腾讯云服务器的 /root/demo.zuo11.com 目录

要配置多环境,可以新开一个 demo-test.zuo11.com 域名,对应一个新的目录 /root/test/demo.zuo11.com,nginx 配置如下

server {
  listen   80;
  server_name  demo.zuo11.com;
  charset  utf-8;
  location / {
    root  /root/demo.zuo11.com;
    index  index.html index.htm;
    if (!-e $request_filename) {
        rewrite ^/(.*) /index.html last;
        break;
    }
  }
}

server {
  listen   80;
  server_name  demo-test.zuo11.com;
  charset  utf-8;
  location / {
    root  /root/test/demo.zuo11.com;
    index  index.html index.htm;
    if (!-e $request_filename) {
        rewrite ^/(.*) /index.html last;
        break;
    }
  }
}

这里有一个坑,就是变量设置时不能勾选 Protected,不然 test 分支触发的 CI/CD 拿不到这个变量

1-28-multi-var-error.png

修改 .gitlab-ci.yml 配置,支持多环境,使用 only 来限制部署的 job,如果是主分支部署到 /root/demo.zuo11.com,如果是 test 分支部署到 /root/test/demo.zuo11.com(注意:第一次操作时,如果服务器没有这个目录,需要在服务器创建)

image: node:16

stages:
  - build
  - deploy

cache: # 缓存
  paths:
    - node_modules

build-job:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist

deploy-job:
  stage: deploy
  image: ringcentral/sshpass:latest
  script:
    - sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no -r ./dist/* $CUSTOM_USERNAME@$CUSTOM_IP:/root/demo.zuo11.com
  only:
    - main

deploy-job-test:
  stage: deploy
  image: ringcentral/sshpass:latest
  script:
    - sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no -r ./dist/* $CUSTOM_USERNAME@$CUSTOM_IP:/root/test/demo.zuo11.com
  only:
    - test

test 分支提交后,部署效果如下,test 分支触发 deploy-job-test 任务,main 分支触发 deploy-job 任务

1-29-multi-var-success.png

部署 koa 接口服务到腾讯云

上面是部署的前端项目,针对后端项目,部署思路如下

  1. 使用 scp 将最新代码 copy 到腾讯云服务器的特定目录
  2. (可选,如果是目标服务器是全新服务器)通过 ssh 执行 shell 命令,安装 node, nginx, pm2。
  3. 通过 ssh 执行 shell 命令:进入该目录,安装依赖,使用 pm2 重启接口服务

这里使用 zuo-config-server koa 接口服务项目来测试,.gitlab-ci.yml 配置如下(ssh 密码、服务器用户名、IP 变量设置这里就不赘述了,上面有介绍过)

image: node:16

stages:
  - deploy

cache: # 缓存
  paths:
    - node_modules

deploy-job:
  stage: deploy
  image: ringcentral/sshpass:latest
  script:
    - ls
    - pwd
    # 1、自动信任主机,执行远程服务器的 "pwd; ls",正好可以查看服务器目录、文件是否正常
    - sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$SERVER_IP "pwd;ls;"

    # 2、将当前项目最新代码,复制到服务器指定目录
    # 查看远程服务器是否有 zuo-config-server 目录,如果没有就创建
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP "mkdir -p zuo-config-server;"
    # copy 当前项目代码到服务器上的 /root/zuo-config-server 目录
    - sshpass -p $PASSWORD scp -r ./* $USER@$SERVER_IP:/root/zuo-config-server

    # 3、执行部署脚本
    # 如果是目标服务器是全新服务器,在服务器上执行项目根目录的 deploy-first.sh 脚本
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy-first.sh
    # 二次部署,在目标服务器执行 deploy.sh 部署脚本
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy.sh

部署脚本 deploy.sh 和 deploy-first.sh 和 .gitlab-ci.yml 都是在项目根目录,如下图

1-30-koa-shell.png

deploy-first.sh,新服务器,首次部署时安装 node、nginx、pm2,下一次部署时,就不用执行了

yum install nodejs npm nginx -y;
npm install -g pm2;

deploy.sh 进入项目目录,安装依赖,使用 pm2 更新接口服务(这里目标服务器没有使用 git,而是在 gitlab shared runners 运行时,将项目最新代码通过 scp 拷贝到远程服务器的指定目录)

# 安装依赖
cd /root/zuo-config-server;
npm install --production;

# 使用 pm2 重启服务
pm2 delete config.zuo11.com;
pm2 start src/index.js -n 'config.zuo11.com';

提交后,即可触发部署,通过服务器 ip、koa 接口服务开启端口 http://47.107.49.197:5000/share/test-deploy,即可成功访问对应的接口,如下图

1-31-api-deploy-success.png

多环境配置

接口服务的多环境,可以使用一台新的服务器来做测试环境,不同的服务器 ip 对应不同的环境、域名

1-32-multi-env-effect.png

上图的 .gitalb-ci.yml 配置如下

  1. 新增了一个 TEST_SERVER_IP 变量表示测试环境的服务器 ip,密码和正式环境服务器一致。
  2. 这里并没有使用 only 来控制分支,而是使用两个 stage、手动触发一键部署。第一个 stage 用于部署到正式环境,第二个 stage 用于部署到测试环境。
image: node:16

stages:
  - deploy-prod
  - deploy-test

deploy-job:
  stage: deploy-prod
  image: ringcentral/sshpass:latest
  script:
    - ls
    - pwd
    - sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$SERVER_IP "pwd;ls;"
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP "mkdir -p zuo-config-server;"
    - sshpass -p $PASSWORD scp -r ./* $USER@$SERVER_IP:/root/zuo-config-server
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy-first.sh
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy.sh
  when: manual

deploy-job:
  stage: deploy-test
  image: ringcentral/sshpass:latest
  script:
    - ls
    - pwd
    - sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$TEST_SERVER_IP "pwd;ls;"
    - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP "mkdir -p zuo-config-server;"
    - sshpass -p $PASSWORD scp -r ./* $USER@$TEST_SERVER_IP:/root/zuo-config-server
    - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP 'bash -s' < ./deploy-first.sh
    - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP 'bash -s' < ./deploy.sh\
  when: manual

test 分支,部署 log 如下图

1-33-exec-log.png

更新代码,二次部署

1-34-api-update-server.png

服务器安装 gitlab runner 进行部署

上面介绍了使用 gitlab 共享 runner 执行 CI/CD 流程进行自动化部署,但共享 runner 的缺点在于有每月运行时长有限制,超过限制如果不付费就不能再使用,另外免费的共享 runner 性能也不高,部署时间相对会久一点。

因此,在自己的服务器上安装 gitlab runner 程序执行 CI/CD 流程,是有必要了解的。这里为了测试,在阿里云创建了一个按量付费的 2核 CPU 4G 内存 5M 带宽 服务器,用于安装 gitlab runner 程序。使用几个小时成本不到 1 元。阿里云 ECS 创建

1-37-2-server.png

使用自定义 runner 部署

在 gitlab 仓库的设置 Settings - CI/CD - Runners 中,可以创建 Project runner,如下图

1-35-project-runner.png

点击新建 runner

  1. 选择安装 gitlab runner 程序的服务器操作系统,使用的是 CenterOs 服务器,选择 Linux
  2. 填写这个 runner 的 tag(这里填的是 dev-zuo),部署任务 Job 与 tag 关联,可以指定仅这个 runner 可以触发该 Job 执行
  3. 可选的 Details,可以给这个 runner 加一个描述

1-36-create-runner.png

填写完上面的信息,点击创建 runner,会进入一个注册 runner 的引导页面,如下图

1-37-register-runner.png

点击 How do I install GitLab Runner,会打开一个弹窗抽屉,教你怎么在服务器安装 gitlab runner 程序,命令如下

默认给的命令会有坑,如果完全按照官方给的执行,后面 CI/CD 会出现执行命令没权限的问题,建议直接使用 root),参考:gitlab-runner 的无权限问题

# 下载 gitlab-runner
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
# 给下载的 gitlab-runner 添加可执行权限
sudo chmod +x /usr/local/bin/gitlab-runner
# (有坑 - 不推荐)创建一个 GitLab Runner 用户
# useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# (有坑 - 不推荐) 安装、运行 gitlab-runner
# gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
# 推荐直接使用 root 用户,方便命令执行,不然 CI/CD 时总是提示没权限
gitlab-runner install --working-directory /home/gitlab-runner --user root
gitlab-runner start

安装完成后,使用页面中给的命令注册 runner,这样可以将这个 runner 与当前的 gitlab 仓库关联

gitlab-runner register
  --url https://gitlab.com
  --token glrt-i8xxxxxxxx # 这里直接 copy 页面中的指令,不同的用户,token 会不一样

运行效果如下图,会让你选择一个 runner executor,指定运行 CI/CD 使用的环境,这里选的 shell

1-38-register-runner-server.png

完成后,进入仓库 - 设置 - Runners 位置,即可看到 runner 状态,如下图

1-39-custom-runner-stats.png

gitlab runner 服务器环境准备

由于上面选择的 excutor(执行器)为 shell,不像 docker 那样可以直接拉去 image 镜像,因此 gitlab runner 运行所依赖的命令都需要在服务器上安装,比如 git、node、npm 等

# 我这里安装 gitlab runner 程序的服务器是 centos 7.6,如果是 ubuntu 需要用 apt-get
# 防止默认安装 git 1.x 版本
sudo yum install https://packages.endpointdev.com/rhel/7/os/x86_64/endpoint-repo.x86_64.rpm -y
# 安装 git、node 等
yum install nodejs npm git -y

1-40-git-install.png

git 版本需要注意,需要是 2.x 版本,不然可能会出现 fatal: git fetch-pack: expected shallow list 错误,参考:CentOS 7 升级 git 版本

1-40-2-git-version.png

部署 vitepress 到 oss(多环境)

这里使用 blog - gitlab 项目来测试,首先在 gitlab runner 所在的服务器安装阿里云 oss 命令行工具

wget http://gosspublic.alicdn.com/ossutil/1.7.3/ossutil64 -O /usr/bin/ossutil64
chmod 755 /usr/bin/ossutil64

修改 .gitlab-ci.yml

  1. 增加 tags 标记,把原先 shared runner 中使用的 docker image 字段删除
  2. 由于 ossutil64 配置会指定 oss bucket 所在的地域 OSS_END_POINT,不同仓库所在的地域可能不一样,这里还是放到配置中,如果你的所有 oss bucket 都是固定在一个地区,可以把这个去掉,直接在服务器执行一次即可。

1-41-oss-multiple.png

上图中的配置如下

stages:
  - deploy-prod
  - deploy-dev

cache: # 缓存
  paths:
    - node_modules

deploy-job-prod:
  stage: deploy-prod
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    # 配置 oss
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com
  when: manual
  artifacts:
    paths:
      - ./.vitepress/dist

deploy-job-dev:
  stage: deploy-dev
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    # 配置 oss
    - ossutil64 config -e $OSS_END_POINT -i $OSS_ACCESS_KEY_ID -k $OSS_ACCESS_KEY_SECRET
    # 部署制品文件到阿里云 oss test-zuo11-com-dev 仓库
    - ossutil64 cp -r -f ./.vitepress/dist oss://test-zuo11-com-dev
  when: manual
  artifacts:
    paths:
      - ./.vitepress/dist
# ossutil64 用法
# -e endpoint, 设置Bucket所在地域的域名信息 OSS_END_POINT
# -i accessKeyID, 访问密钥的一部分,用于标识用户身份,以对命令请求进行身份验证。OSS_ACCESS_KEY_ID
# -k accessKeySecret, 访问OSS使用的访问凭证。OSS_ACCESS_KEY_SECRET

在 Job 中可以看到 runner 的 tag 标记 1-42-oss-job.png

部署到,效果如下

1-43-oss-deploy-effect.png

部署 vue3 项目到其他服务器(多环境)

这里使用 zuo-config-fe - gitlab 前端项目进行部署测试。之前创建的 runner 是在 blog 这个仓库,在这个账号的 zuo-config-fe 这个仓库,设置中也能看到这个 runner,点击 enable for this project 就可以使用这个 runner 了。

1-44-custom-runner-other-repo.png

部署到其他服务器,这里用的 ssh 登录密码方式连接服务器,需要使用 sshpass 命令,要先在 gitlab runner 所在服务器进行安装

yum install sshpass -y # CenterOS 安装命令, ubuntu 使用 apt-get

修改 .gitlab-ci.yml 配置,效果如下图

1-45-vue3-custom-runner.png

stages:
  - deploy-main
  - deploy-test

cache: # 缓存
  paths:
    - node_modules

deploy-job:
  stage: deploy-main
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    - sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no -r ./dist/* $CUSTOM_USERNAME@$CUSTOM_IP:/root/demo.zuo11.com
  when: manual
  artifacts:
    paths:
      - dist

deploy-job-test:
  stage: deploy-test
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    - sshpass -p $PASSWORD scp -o StrictHostKeyChecking=no -r ./dist/* $CUSTOM_USERNAME@$CUSTOM_IP:/root/test/demo.zuo11.com
  when: manual
  artifacts:
    paths:
      - dist

部署成功后,效果如下图

1-46-vue3-proj-deploy.png

部署 vue3 项目到当前服务器

上面是使用 ssh 部署到其他服务器,如果是部署到 gitlab runner 程序所在的服务器,那就只需要把构建产物,复制到指定目录就可以了,如果执行 mkdir 等命令没权限,参考:gitlab-runner 的无权限问题

stages:
  - deploy-main
  - deploy-test

cache: # 缓存
  paths:
    - node_modules

deploy-job:
  stage: deploy-main
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    - pwd;mkdir -p /root/prod/zuo-config-fe;
    - rm -rf /root/prod/zuo-config-fe/*;cp -r ./dist/* /root/prod/zuo-config-fe/;
  when: manual
  artifacts:
    paths:
      - dist

deploy-job-test:
  stage: deploy-test
  tags:
    - dev-zuo
  script:
    - npm install
    - npm run build
    - pwd;mkdir -p /root/test/zuo-config-fe;
    - rm -rf /root/test/zuo-config-fe/*;cp -r ./dist/* /root/test/zuo-config-fe/;
  when: manual
  artifacts:
    paths:
      - dist

部署 koa 接口服务到腾讯云

这里还是使用 zuo-config-server koa 接口服务来测试部署,把上面使用 gitlab 共享 runner 部署的配置稍微修改下即可

1-47-custom-runner-api.png

stages:
  - deploy-prod
  - deploy-test

deploy-job:
  stage: deploy-prod
  tags:
    - dev-zuo
  script:
    - ls
    - pwd
    - sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$SERVER_IP "pwd;ls;"
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP "rm -rf zuo-config-server;mkdir -p zuo-config-server;"
    - sshpass -p $PASSWORD scp -r ./* $USER@$SERVER_IP:/root/zuo-config-server
    # - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy-first.sh
    - sshpass -p $PASSWORD ssh $USER@$SERVER_IP 'bash -s' < ./deploy.sh
  when: manual

deploy-job-test:
  stage: deploy-test
  tags:
    - dev-zuo
  script:
    - ls
    - pwd
    - sshpass -p $PASSWORD ssh -o StrictHostKeyChecking=no $USER@$TEST_SERVER_IP "pwd;ls;"
    - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP "rm -rf zuo-config-server;mkdir -p zuo-config-server;"
    - sshpass -p $PASSWORD scp -r ./* $USER@$TEST_SERVER_IP:/root/zuo-config-server
    # - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP 'bash -s' < ./deploy-first.sh
    - sshpass -p $PASSWORD ssh $USER@$TEST_SERVER_IP 'bash -s' < ./deploy.sh
  when: manual

部署后,效果如下图

1-48-deploy-effect.png

执行 log

1-49-log.png

两种 runner 部署耗时比对

从上面的截图可以看出自定义 runner 比共享 runner 部署耗时短很多,下面是一些数据对比

类别 gitlab 共享 runner 在自己服务器上安装 gitlab runner
oss 部署耗时 03:14 / 01:25(二次) 00:45
vue3 前端项目部署耗时 04:20 / 02:28(二次) 00:46
koa 接口部署耗时 02:57 / 01:10(二次) 00:19

总结

上面使用 gitlab 共享 runner、自定义 runner 分别对三个项目进行了多环境 CI/CD 自动化部署实践