Skip to main content

GitLab

CI/CD 相关技巧

gitlab-ci 模板文件参考

十分原始,但可做语法参考。 https://gitlab.com/gitlab-org/gitlab-foss/tree/master/lib/gitlab/ci/templates

查看可用的 CI 变量

打印所有可用的变量: https://docs.gitlab.com/ee/ci/variables/index.html#list-all-environment-variables

先在 before_script 打印出所有变量,方便开发调试:

before_script:
- export

变量对照表,一定要多看变量的详解,只看变量名很难知道实际意义: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html

指定依赖任务

默认的任务执行顺序并不是由上往下的,而是根据任务名称的 ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)编码作为排序标准。

虽然我们可以为 stages 指定执行顺序,例如完成 test 阶段再执行 build 阶段。

但同一个 stage 里面的 job 就要用 needs 去定义了:

job_2:
needs:
- job: job_1

在 docker-in-docker(dind) 里使用私有 Docker Registry

前置条件:

  • 使用 GitLab 的 Container Registry 做 Docker 私库 。
  • 私库通过 https://registry.gitlab.xxx.com 可正常访问。
  • 已取得该 registry 及 gitlab 的 TLS 证书并保存到 CI 变量中。

必须在 variables 配一个同名变量, 否则 services 的 command 执行时拿不到想要的变量:

variables:
DOCKER_REGISTRY_CA: "$DOCKER_REGISTRY_CA"
GITLAB_CA: "$GITLAB_CA"

dind(docker-in-docker) 必须要配在 services 里面,不能配在 job 的 image 里:

services:
- name: docker:20.10.8-dind
command:
- /bin/sh
- -c
- echo "$DOCKER_REGISTRY_CA" > /usr/local/share/ca-certificates/registry.crt && echo "$GITLAB_CA" > /usr/local/share/ca-certificates/gitlab.crt && update-ca-certificates && dockerd-entrypoint.sh || exit

job 的 image 应写具体的已装有 docker(能使用 docker 命令)的非 dind 镜像名:

job-using-private-registry:
image: docker:20.10.8

没配好的话会出现如下错误:

Get "https://registry.gitlab.xxx.com/v2/": x509: certificate signed by unknown authority

Docker 私库 pull/push 时报 access forbidden 的错误

必须提前 docker login,否则在 pull/push 私库的镜像时会报 access forbidden 的错误:

Head "https://registry.gitlab.xxx.com/v2/your-group/your-project/manifests/latest": denied: access forbidden

before_script:
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY

在 UI 上配的 CI 变量值不要含有 $ 美元号

无论 CI 变量的 Type 是 File 还是 Variable,变量值里面所有 $ 号开头的都会当成变量,要特别注意。

例如:若有个字符串 '@^$BDD$@iieurdjsf' 则被 CI 二次处理后最终输出的是 '@iieurdjsf'

因此,要特别注意,CI变量值内的数据库密码等带有特殊字符串的内容,不要有 $ 号出现。

另外可用 Gitlab 的转义字符 $$ 手动替换所有 $,例如:'@^$$BDD$$@iieurdjsf',最终输出的是 '@^$BDD$@iieurdjsf'。这方法不太实际,不推荐。

参考:https://gitlab.yitasoft.com/help/ci/variables/index#use-the-character-in-variables

GitLab 会为已创建的 Job 存当时的环境变量作为上下文

以下按时间顺序方便理解:

  1. 假设在 UI 界面配置了自定义 CI 变量 PORT=111。
  2. Job 888 被创建并执行,在该任务中取得的 $PORT 等于 111。
  3. 在 UI 界面将自定义 CI 变量 PORT 改为 222。
  4. 重新执行该 Job 888,但在该任务中取得的 $PORT 还是等于 111。
  5. 创建新 Job 999,在该任务中取得的 $PORT 等于最新的值 222。

不要在 CI 任务中操作远程服务器的代码仓库

假设:

  • 触发 CI 之前的最近的一次 commit 是 20160201
  • 当前触发 CI 的 commit 是 20160204
  • 用日期数字做假设,方便体现它们时间上的先后顺序

任务执行过程中,在其它分布式 git 仓库 fetch 到的最新版本是 20160201,并非 20160204。

需要等任务执行成功,其它分布式 git 仓库 fetch 到的才是 20160204。

因此,不要在 CI 任务中操作远程服务器的代码仓库,因为你无法拿到最新代码。

万能的 $CI_JOB_TOKEN

在流水线脚本里面,利用 $CI_JOB_TOKEN 可以访问 GitLab 的 API。

注意 Header 值是 "JOB-TOKEN: $CI_JOB_TOKEN" 非 PRIVATE-TOKEN。

script 中有特殊字符时,要用单引号包裹整行命令

命令里面有特殊字符 : 冒号,会当成 yaml 语法的键值对,导致 gitlab 报错,因此必须将整个命令放到单/双引号中。

详见:https://docs.gitlab.com/ee/ci/yaml/script.html#use-special-characters-with-script

示例:

job:
script:
- "curl_header='JOB-TOKEN: '$CI_JOB_TOKEN"
- curl --output dist.zip --location --header "$curl_header" "https://gitlab.example.com/api/v4/projects/47474/jobs/artifacts/master/raw/xxx.zip?job=release"

注意:

  • 分两步去写,特殊处理的部分单独作为一条命令,更清晰。
  • curl 里面的 --header 值会有特殊字符和空格,因此必须用引号括住,即 "$curl_header"
  • 当然写成一行也行,不推荐:'curl --output dist.zip --location --header "JOB-TOKEN: "${CI_JOB_TOKEN} "https://gitlab.yitasoft.com/api/v4/projects/24/jobs/artifacts/master/raw/dist.zip?job=release-zip"'