4. CI/CD 变量类型:分类与优先级
在 GitLab CI 流水线中,变量是驱动参数化配置的核心。理解变量的分类体系与优先级规则,是构建可复用、可维护服务目录的基础。本章将系统梳理 GitLab CI 变量的四种主要类型,并解析其覆盖与合并机制。
4.1 变量分类全景
GitLab CI 变量按作用域与存储方式可分为以下四类:
| 变量类型 | 作用域 | 存储位置 | 典型用途 |
|---|---|---|---|
| 项目变量 | 单个项目 | 项目设置 → CI/CD → 变量 | 数据库连接串、部署令牌、环境专属配置 |
| 组变量 | 组内所有项目 | 组设置 → CI/CD → 变量 | 共享凭证、通用构建参数、合规性标记 |
| 实例变量 | 整个 GitLab 实例 | 管理员 → 设置 → CI/CD → 变量 | 全局代理、镜像仓库地址、许可证密钥 |
| 文件变量 | 按项目/组/实例 | 与上述相同,类型选 "File" | 证书文件、SSH 私钥、Kubeconfig |
实践建议:在服务目录中,优先将环境无关的通用参数(如镜像仓库域名)定义为组变量或实例变量,将环境敏感参数(如数据库密码)定义为项目变量,实现职责分离。
4.2 变量优先级规则
当多个作用域定义了同名变量时,GitLab 按照以下优先级从高到低进行覆盖:
- 触发变量(手动流水线、API 触发时传入)
- 作业级变量(
variables关键字在 job 内定义) - 流水线级变量(
variables关键字在.gitlab-ci.yml顶层定义) - 项目变量(UI 或 API 设置)
- 组变量(父组优先于子组)
- 实例变量
- 预定义变量(如
CI_COMMIT_REF_NAME)
常见陷阱:组变量与项目变量同名时,项目变量始终覆盖组变量,无论组层级高低。若需强制组变量生效,应使用
environment_scope 或避免在项目层定义同名变量。
4.3 变量优先级与覆盖流程
下图展示了变量从定义到最终生效的完整解析路径:
4.4 文件变量的特殊处理
文件变量(Type: File)在存储与引用方式上与普通变量有显著差异:
- 存储方式:变量值被写入一个临时文件,而非直接作为字符串注入。
- 引用方式:通过
$变量名获取的是文件路径,而非文件内容。 - 读取内容:需使用
cat $变量名或$(cat $变量名)获取实际值。 - 典型场景:SSH 私钥、Kubernetes kubeconfig、TLS 证书、GPG 密钥。
服务目录最佳实践:在服务目录模板中,将证书类参数统一声明为文件变量,并在
before_script 中通过 cat 写入标准路径,避免硬编码。
4.5 变量作用域与可见性对比
| 特性 | 项目变量 | 组变量 | 实例变量 | 文件变量 |
|---|---|---|---|---|
| 可见范围 | 单个项目 | 组及子组所有项目 | 整个实例 | 同左(按设置范围) |
| 是否可被覆盖 | 是(仅被更高优先级覆盖) | 是(被项目变量覆盖) | 是(被组/项目覆盖) | 是(遵循同优先级规则) |
| 是否支持掩码 | 是 | 是 | 是 | 否(文件内容不掩码) |
| 环境作用域 | 支持 | 支持 | 不支持 | 支持 |
| API 管理 | 支持 | 支持 | 支持 | 支持 |
4.6 变量优先级在服务目录中的应用
在服务目录参数配置中,合理利用变量优先级可实现灵活的配置覆盖:
# .gitlab-ci.yml 服务目录模板示例
variables:
DEPLOY_ENV: "staging" # 流水线级默认值
IMAGE_TAG: "latest"
deploy-job:
variables:
DEPLOY_ENV: "production" # 作业级覆盖流水线级
script:
- echo "Deploying to $DEPLOY_ENV"
- echo "Image tag: $IMAGE_TAG"
environment:
name: $DEPLOY_ENV
层级覆盖策略:在服务目录中,建议将全局默认值定义为组变量,项目定制值定义为项目变量,临时覆盖值通过流水线触发变量传入。这样既保证了基线一致性,又保留了灵活覆盖的能力。
4.7 变量优先级与合并行为
理解变量优先级后,还需掌握同名变量的合并行为:
- 完全覆盖:高优先级变量直接替换低优先级同名变量,不会合并。
- 数组变量:若变量值为数组(如
VAR: ["a", "b"]),高优先级数组会整体替换低优先级数组。 - 环境作用域:当变量设置了
environment_scope,仅匹配该环境的作业才会使用该变量,优先级规则在匹配范围内生效。
下图展示了不同作用域变量在流水线中的合并与覆盖关系:
关键提醒:当组变量与项目变量同名时,项目变量会完全覆盖组变量,不会进行值合并。若需要组变量作为后备值,应在项目层不定义该变量,或使用
environment_scope 进行环境隔离。