likes
comments
collection
share

精通 GitLab CI:打造高效的持续集成环境

作者站长头像
站长
· 阅读数 60

GitLab CI

GitLab CI(Continuous Integration)是GitLab提供的持续集成和持续交付(CI/CD)平台。它允许开发团队自动化地构建、测试和发布软件,以减少手动操作和加快交付速度。

精通 GitLab CI:打造高效的持续集成环境

下面是GitLab CI的一些主要特点和功能:

  1. 集成版本控制:GitLab CI与GitLab代码仓库紧密集成,可以直接从仓库中触发CI流水线,并与代码变更进行关联。

  2. 基于流程的管道:通过在.gitlab-ci.yml文件中定义流水线的各个阶段和任务,可以创建复杂的CI/CD流程。这些流程可以包括构建、测试、静态代码分析、部署等。

  3. 多个执行器:GitLab CI支持多种执行器,包括Shell、SSH、Docker、Kubernetes等,以满足不同的环境需求。

  4. 并行构建:可以同时运行多个作业,加快构建和测试的速度。

  5. 集成测试:可以方便地集成各种测试框架,如单元测试、端到端测试、性能测试等。

  6. 自动化部署:可以将构建好的应用程序或容器直接部署到目标环境,实现自动化的部署过程。

  7. 实时日志和报告:在CI/CD过程中,实时监视和查看作业的日志和报告,方便排查问题和分析结果。

  8. 可扩展性:GitLab CI具有灵活的插件系统,可以根据需要添加各种自定义插件和扩展功能。

通过使用GitLab CI,团队可以更快地构建和测试代码,并实现自动化的软件交付流程。这有助于提高代码质量、减少错误和缺陷,并加速产品的发布周期。

咱们分为以下几步学习并实现一个GitLab工作流

  • 第一步:了解并创建Runner
  • 第二步:了解.gitlab-ci.yml中常用字段api
  • 第四步:使用内置环境变量和自己项目设置默认变量
  • 第三步:实战化项目持续集成

第一步 了解创建 Runner

GitLab CI Runner是GitLab CI/CD系统的一部分,它起着将CI/CD流水线中定义的任务和作业实际执行的作用。具体来说,GitLab CI Runner有以下几个重要的作用:

  1. 执行构建和测试任务:在GitLab CI/CD流程中,Runner负责运行定义的作业,例如代码编译、单元测试、集成测试等。Runner会根据配置从GitLab项目中拉取代码,并在指定的环境中执行这些任务。

  2. 提供多种执行环境:GitLab CI Runner支持不同类型的执行器,包括Shell、Docker、Kubernetes等。这意味着您可以根据需要选择合适的执行环境来执行任务,以确保环境一致性并满足特定的依赖需求。

  3. 并发执行和扩展性:GitLab CI Runner支持并发执行多个作业,可以有效地利用计算资源。您可以在需要时增加更多的Runner实例来扩展并发性和处理能力,以应对大规模的构建和测试需求。

  4. 日志和报告生成:Runner会生成详细的执行日志,记录每个作业的输出和结果。这些日志非常有用,可以帮助您排查问题、分析构建过程,并及时获得失败或错误的报告。这些日志和报告也可以在GitLab界面上可视化显示。

  5. 集成第三方工具和服务:GitLab CI Runner可以与各种其他工具和服务集成,例如代码质量检测工具、部署工具、通知服务等。这使得您可以通过Runner来自动化整个CI/CD流程,并将结果集成到其他系统中。

GitLab CI Runner的作用是将定义在GitLab CI/CD配置文件中的任务实际执行起来。

创建GitLab Runner

GitLab是不带Runner的需要自己去定义生成自己的Runner。友情提示,Gitlab的安装尽量不要和Gitlab Runner程序在一台服务器上,另外Gitlab Runner程序比较占用系统CPU。

  1. 下载对应的 Gitlab Runner 版本:
# Linux x86-64
wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64

# Linux x86
wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386

# Linux arm
wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm
  1. 赋予它执行的权限(Give it permissions to execute):
sudo chmod +x /usr/local/bin/gitlab-runner
  1. 创建一个GitLab CI用户(Create a GitLab CI user):
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
  1. 作为服务安装和运行(Install and run as service):
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start

第二步:.gitlab-ci.yml中常用关键字

在你的项目根目录创建一个.gitlab-ci.yml文件。它是一个YAML文件,您可以在其中指定GitLab CI/CD的指令。内容如下:

CI文件中,我们可以对一系列任务做定义,每个任务至少需要包含一条可执行的语句,在 script 定义 Runner 环境可执行的所有语句,每一个任务都会按照定义顺序执行。

# 定义 stages
stages:
  - build
  - test

# 定义build job
build-job:
  stage: build
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"

# 定义test job
test-job1:
  stage: test
  script:
    - echo "This job tests something"

stages 定义构建任务

stages关键字用于定义构建场景,可以被构建任务引用定义自己的构建场景,stages定义的顺序也决定了任务执行的顺序,下面给出一个基本的场景示例

# 定义 stages
stages:
    - test
    - build
    - publish
  • 首先所有任务的构建场景为 test 的任务全部并行执行
  • 接着会执行构建场景为 build 的所有任务
  • 最后执行构建场景为 publish 的所有任务
  • 其中任何一个任务失败,整个流水线会失败,并且之后的任务不会执行

stages 可以不被定义,那么程序会默认为 test build deploy 三个场景,如果一个任务没有指定自己的 stage,那么它将默认使用 test

Jobs

Jobs 表示构建工作,表示某个 Stage 里面执行的工作。 我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

  • 相同 Stage 中的 Jobs 会并行执行;
  • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功;
  • 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

所以,Jobs 和 Stage 的关系图就是:

+------------------------------------------+
|                                          |
|  Stage 1                                 |
|                                          |
|  +---------+  +---------+  +---------+   |
|  |  Job 1  |  |  Job 2  |  |  Job 3  |   |
|  +---------+  +---------+  +---------+   |
|                                          |
+------------------------------------------+

script

用来定义一个任务中需要执行的shell脚本

script:
	- npm install
    - npm run lint
    - npm run build

before_script

定义任何 Jobs 运行前都会执行的命令。

before_script:
    - npm install
    - echo 'Install successful'

after_script

定义任何 Jobs 运行完后都会执行的命令。

after_script:
    - xxxxxx # 通知所有用户完成构建

variables && Job.variables

定义环境变量。 如果定义了 Job 级别的环境变量的话,该 Job 会优先使用 Job 级别的环境变量。

variables:
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'

# 定义build job
build-job:
  variables: 
    TEST: '测试'
  stage: build
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo ${BUILD_SUCCESS}
    - echo ${SUCCESS}
    - echo ${TEST}

image

image 关键字允许当前CI程序基于某个Docker镜像中运行,当然前提是你的任务指定的tags必须是以Docker形式注册的Github RunnerCI程序会默认在你本地寻找镜像,如果不存在的话,则会从Docker Hub拉取。

variables:
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'

# 定义build job
build-job:
  # 以下面这个镜像运行script
  image: node:2.8.1
  variables: 
    TEST: '测试'
  stage: build
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo ${BUILD_SUCCESS}
    - echo ${SUCCESS}
    - echo ${TEST}

only && except

这两个关键字定义任务什么时候将会被创建

  1. only 定义了任务需要执行的所在分支或者标签;
  2. except 定义了任务不会执行的所在分支或者标签;
variables:
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'

# 定义build job
build-job:
  # 以下面这个镜像运行script
  image: node:2.8.1
  variables: 
    TEST: '测试'
  stage: build
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo ${BUILD_SUCCESS}
    - echo ${SUCCESS}
    - echo ${TEST}
   only:
   # 可以指定多个再mester、dev、或者打tag 都会运行该CI工作流    
    - master 
    - dev
    - tags

    # only: 或者可以这么写判断 校验尼的tag符合正则的才会触发
    # variables:
    #   - $CI_COMMIT_TAG =~ /^[0-9]+\.[0-9]+\.[0-9]+(-rc(\..+)?)?$/
   except:
    - feature/**

两者如果都存在在一个任务声明中,则所需引用将会使用两者交集过滤。 两者均允许使用正则。

tags

指定当前任务适用的 runners, 必须是已经注册过的runner才能指定

variables:
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'

# 定义build job
build-job:
  # 以下面这个镜像运行script
  image: node:2.8.1
  variables: 
    TEST: '测试'
  stage: build
  script:
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo ${BUILD_SUCCESS}
    - echo ${SUCCESS}
    - echo ${TEST}
   only:
   # 可以指定多个再mester、dev、或者打tag 都会运行该CI工作流    
    - master 
    - dev
    - tags

   except:
    - feature/**

   tags:
    - ci-runnner

artifacts

定义 Job 中生成的附件。 当该 Job 运行成功后,生成的文件可以作为附件 (如生成的二进制文件) 保留下来,打包发送到 GitLab,之后我们可以在 GitLab 的项目页面下下载该附件。

variables:
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'
  FILE_NAME: 'dist.zip'

# 定义build job
build-job:
  # 以下面这个镜像运行script
  image: node:2.8.1
  variables: 
    TEST: '测试'
  stage: build
  script:
    - npm run build
    - cd dist/ && zip -r dist.zip ./* && mv dist.zip ../ && cd -
    - echo "Hello, $GITLAB_USER_LOGIN!"
    - echo ${BUILD_SUCCESS}
    - echo ${SUCCESS}
    - echo ${TEST}
   only:
   # 可以指定多个再mester、dev、或者打tag 都会运行该CI工作流    
    - master 
    - dev
    - tags
   except:
    - feature/**

   artifacts:
    paths:
      - ${FILE_NAME}
   tags:
    - ci-runnner

cache && Job.cache

定义需要缓存的文件。 每个 Job 开始的时候,Runner 都会删掉 .gitignore 里面的文件。 如果有些文件 (如 node_modules/) 需要多个 Jobs 共用的话,我们只能让每个 Job 都先执行一遍 npm install。 这样很不方便,因此我们需要对这些文件进行缓存。缓存了的文件除了可以跨 Jobs 使用外,还可以跨 Pipeline 使用。

stages:
  - build

cache:
  paths:
    - node_modules/

job1:
  stage: build
  script:
    - npm install
    - npm run build

job2:
  stage: build
  script:
    - npm install
    - npm run test

allow_failure

allow_failure 关键字用于标记一个Job(作业)是否允许失败。当设置为true时,如果该Job失败了,整个流水线(pipeline)的状态仍将被标记为成功(success),而不会影响后续的Jobs

stages:
  - test

job1:
  stage: test
  script:
    - run_tests.sh

job2:
  stage: test
  script:
    - run_integration_tests.sh
  allow_failure: true

dependencies

dependencies 关键字用于定义作业(Job)之间的依赖关系。它指定了某个作业必须在哪些其他作业完成后才能执行。

variables:
  FILE_NAME: dist.zip

stages:
  - build
  - deploy

build:
  stage: build
  only:
    - tags
  script:
    - yarn && yarn build
    - cd dist/ && zip -r dist.zip ./* && mv dist.zip ../ && cd -
    - ls
  artifacts:
     # expire_in 产物保留多少天
    expire_in: 30 days
    paths:
      - ${FILE_NAME}
  tags:
    - runner

deploy:
  stage: deploy
  script: 
    # - 部署相关命令
    - echo "project done"
  only:
    - tags

  # dependencies build 留下来的dist产物
  dependencies:
    - build
  tags:
    - runner

以上就是经常使用的一些关键字了,如果不能满足使用可以去官网去查看: 地址

第三步:内置环境变量和项目自定义环境变量

GitLab CI中有一些内置的环境变量简单说几个如下:

  • CI_PROJECT_NAME(当前正在构建的项目名称)
  • CI_COMMIT_TAG (commit 的 tag 名称,任务对应的 tag)
  • CI_COMMIT_REF_NAME(用于构建项目的分支或Git tag名称)
  • CI_REPOSITORY_URL (Git 仓库地址)
  • GITLAB_USER_EMAIL (触发CI的用户邮箱)

你也可以使用 export 关键字打印出所有的变量,需要注意的是,该关键字也会打印出任务中定义的所有私有变量

job:
    script:
        - export

内置变量打印的例子如下:

export CI_JOB_ID = '50'
export CI_COMMIT_SHA = 'XXXX'
export CI_COMMIT_SHORT_SHA = 'XXX'
export CI_COMMIT_REF_NAME = 'master'
export CI_REPOSITORY_URL = 'XXXX'
export CI_COMMIT_TAG = '1.0.0'
export CI_JOB_NAME = 'XXX'
export CI_JOB_STAGE = 'XX'
export CI_JOB_MANUAL = 'XX'
export CI_JOB_TRIGGERED = 'XX'
export CI_JOB_TOKEN = 'XXX'
export CI_PIPELINE_ID = 'XX'
export CI_PIPELINE_IID = 'XX'
export CI_PAGES_DOMAIN = 'XX'
export CI_PAGES_URL = 'XX'
export CI_PROJECT_ID = 'XX'
export CI_PROJECT_DIR = 'XX'
export CI_PROJECT_NAME = 'XX'
export CI_PROJECT_TITLE = 'XX'
export CI_PROJECT_NAMESPACE = 'XX'
export CI_PROJECT_PATH = 'XX'
export CI_PROJECT_URL = 'XX'
export CI_REGISTRY = 'XX'
export CI_REGISTRY_IMAGE = 'XX'
export CI_REGISTRY_USER = 'XX'
export CI_REGISTRY_PASSWORD = 'XX'
export CI_RUNNER_ID = 'XX'
export CI_RUNNER_DESCRIPTION = 'XX'
export CI_RUNNER_TAGS = 'docker, linux'
export CI_SERVER = 'yes'
export CI_SERVER_URL = 'https://example.com'
export CI_SERVER_HOST = 'example.com'
export CI_SERVER_PORT = '443'
export CI_SERVER_PROTOCOL = 'https'
export CI_SERVER_NAME = 'GitLab'
export CI_SERVER_REVISION = '70606bf'
export CI_SERVER_VERSION = '8.9.0'
export CI_SERVER_VERSION_MAJOR = '8'
export CI_SERVER_VERSION_MINOR = '9'
export CI_SERVER_VERSION_PATCH = '0'
export GITLAB_USER_EMAIL = 'CC'
export GITLAB_USER_ID = '42'

除了使用内置环境变量、使用variables关键字定义的变量外,还可以再当前项目创建变量如下:

精通 GitLab CI:打造高效的持续集成环境

创建后也可以直接使用如下:

variables:
  FILE_NAME: dist.zip

stages:
  - build

build:
  stage: build
  script:
    - echo ${FILE_NAME} # variables 定义的变量
    - echo ${CI_PROJECT_NAME} # 内置变量
    - echo ${TEST_KEY} # 在项目下面自定义的变量
  tags:
    - runner

还可以再GitLab一个目录分组下创建该目录下的公共环境变量公共环境变量可以再当前分组下面的项目都可以直接使用,用法跟再项目下面自定义变量一样。

第四步:实战化

GitLab CI的目的是定义一些工作流,自动化地构建、测试和发布软件,以减少手动操作和加快交付速度。再不用工作流的时候大家都怎么交付的呢?

  1. 本地yarn build,然后把打包出来的dist交给后端同学部署,又或者自己部署到环境上。

  2. 本地yarn build,然后把打包出来的dist提交到后端仓库指定的静态资源目录下面,然后由后端整体打包构建服务。

  3. 使用jenkins帮你打包部署,执行定义好的工作流。

咱们先说说3的问题为何使用GitLab CI代替jenkins的优势:

  1. 每次构建任务需要去jenkins点一下。
  2. 使用GitLabwebhooks监听push等动作来触发jenkins执行的(这个先不在这里细说了),多了一步。
  3. 无法使用Gitlab的内置的环境变量。

后面我们就把重心都切到了GitLab CI上面了,那么咱们回到正题如何使用GitLab CI工作流分别帮咱们使用1,2呢?

第一种: 直接把静态资源部署到开发、生产服务器上

同步本地和目标服务器的插件咱们使用rsyncansible-playbooksshpass等来实现用脚本登录服务器操作静态资源文件

如果本机或者远程计算机没有安装 rsync,可以用下面的命令安装。注意,传输的双方都必须安装 rsync。

# Debian
$ sudo apt-get install rsync

# Red Hat
$ sudo yum install rsync

# Arch Linux
$ sudo pacman -S rsync

使用方法看阮一峰rsync 用法教程

variables:
  FILE_NAME: dist.zip

stages:
  - build

build:
  stage: build
  script:
    - yarn && yarn build
    - cd dist/ && zip -r dist.zip ./* && mv dist.zip ../ && cd -
    - ls

  artifacts:
     # expire_in 产物保留多少天
    expire_in: 30 days
    paths:
      - ${FILE_NAME}
  tags:
    - runner

deploy:
  stage: deploy
  script: 
    - sudo rsync
    - echo "project done"
  only:
    - tags
  dependencies:
    - build
  tags:
    - runner

第二种: 交到后端仓库指定的静态资源目录

定义工作流直接把代码打包,然后把dist文件夹上传到后端工程里面(后端git仓库)。如下:

variables:
  USER_NAME: '你的用户名(需要跟你git的保持一致)'
  USER_EMAIL: '你得邮箱(需要跟你git的保持一致)'
  BRANCH: ${CI_COMMIT_REF_NAME}
  BUILD_SUCCESS: '打包执行成功'
  SUCCESS: 'job执行完成'
   
stages:
  - prod_deploy
 
prod_deploy:
  stage: prod_deploy
  script:
    # 打包-配置
    - npm -v
    - yarn && yarn build
    - ls
    - echo ${BUILD_SUCCESS}
    # - ssh-Key-配置
    - mkdir ~/.ssh -p
    - chmod 700 ~/.ssh
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
    - eval $(ssh-agent -s)
    # # PRIVATE_SSH_KEYE 在该仓库中定义的变量
    - echo ${PRIVATE_SSH_KEYE};
    - ssh-add <(echo "$PRIVATE_SSH_KEYE")
    - git config --global user.name ${USER_NAME};
    - git config --global user.email ${USER_EMAIL};
    - echo ${BRANCH};
    # 推送仓库配置
    - ls
    - cd .ci && yarn
    # node 提交git 脚本再下面文件中
    - node index
    - echo ${SUCCESS}

  only:
    - master
 
  #dependencies:  表示依赖关系的
  artifacts:
    paths:
      - ${FILE_NAME}
  tags:
    - runner

${PRIVATE_SSH_KEYE}是你本地的ssh私钥,放在了自定义变量里面。以下命令获取私钥:

cd ~/.ssh
cat id_rsa

大概node脚本就是如下流程:

  1. 拉取后端仓库切换到要提交的分支;
  2. 删除原本的前端静态资源;
  3. 复制新打包出来的资源到后端仓库里面;
  4. git提交;
  5. 删除拉下来的后端仓库;
// node inde
const chalk = require('chalk');
const shell = require('shelljs');
const { log } = console;

const FULL_NAME = '你的打包后的文件名称';
const GIT_PATH = 'clone的后端的ssh地址';
const GIT_BRANCH = '后端仓库要提交的分子';
const PROJECT_AS_NAME = 'project-clone';

function deploy() {
  // 上传git
  shell.rm('-rf', `${PROJECT_AS_NAME}/`);
  shell.exec('git config user.name');
  shell.exec(`git clone ${GIT_PATH} -b ${GIT_BRANCH} ${PROJECT_AS_NAME}`);

  shell.exec('ls');
  shell.cd(PROJECT_AS_NAME);
  shell.rm('-rf', `${FULL_NAME}/`);
  shell.rm('-rf', `${FULL_NAME}/`);
  shell.cp('-R', `../../${FULL_NAME}`, `${FULL_NAME}`);

  shell.exec('pwd');
  shell.exec('git add .');
  shell.exec('git status');
  log(chalk.blue('git add 成功!'));
  //这里是运行的sh 文件 放下面了   
  shell.exec('sh ../command.sh');
  log(chalk.blue('git commit 成功!'));
  shell.exec('git push');
  shell.cd('..');
  shell.exec('pwd');
  shell.rm('-rf', `${PROJECT_AS_NAME}/`);
  shell.rm('-rf', `${FULL_NAME}`);
  log(chalk.blue('git 推送成功!'));
}


deploy();

由于没办法使用node脚本提交git commit把该指令放在了sh文件中如下:

#!/bin/bash
git commit -m $'feat:前端更新'

echo 'commit success'

以上只是适合我的工作中的应用场景,可以参考下定制属于自己的工作流。其实还有些其他常见的流程比如:再项目推送完成后可以向项目组上的人发送邮件,通知他们部署成功,又或者可以调用钉钉webhooks等达到一个通知的功能。

总结

以上就是GitLab CI的知识点了,如果对你有帮助,欢迎点赞收藏。

参考链接:

转载自:https://juejin.cn/post/7250386282400628797
评论
请登录