如何减少多环境下GitLab CI带标签配置的重复代码?
重构GitLab CI Terraform作业配置的方案
核心思路
通过集中式环境配置映射+单一通用作业的方式,将所有环境的差异项(extends模板、needs依赖、Runner标签、环境变量)统一管理,避免重复定义多个作业。
方案1:JSON映射+动态变量提取(推荐,易于维护)
适合需要频繁新增/修改环境的场景,所有环境配置集中在一处,新增环境只需修改映射内容。
# 1. 集中定义所有环境的差异配置 variables: # 用JSON存储环境与属性的映射,方便用jq提取 ENV_MAPPING: | { "main": { "runner_tags": "prod-runner", "tf_extends": ".terraform-prod", "tf_needs": ["build-prod"], "tf_env_vars": {"TF_VAR_ENV": "prod", "TF_WORKSPACE": "prod"} }, "staging": { "runner_tags": "staging-runner", "tf_extends": ".terraform-staging", "tf_needs": ["build-staging"], "tf_env_vars": {"TF_VAR_ENV": "staging", "TF_WORKSPACE": "staging"} }, "dev": { "runner_tags": "dev-runner", "tf_extends": ".terraform-dev", "tf_needs": ["build-dev"], "tf_env_vars": {"TF_VAR_ENV": "dev", "TF_WORKSPACE": "dev"} } } # 统一目标分支:优先取MR目标分支,否则用当前提交分支 TARGET_BRANCH: "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-$CI_COMMIT_BRANCH}" # 2. 定义通用Terraform作业模板(所有重复逻辑) .terraform-base: script: - terraform init - terraform plan - terraform apply -auto-approve artifacts: paths: - terraform.tfstate expire_in: 7d cache: paths: - .terraform/ # 3. 单一通用作业,动态加载对应环境的配置 terraform-deploy: # 动态继承环境专属模板+通用模板 extends: ["$TF_EXTENDS", ".terraform-base"] # 动态设置Runner标签 tags: ["$RUNNER_TAGS"] # 动态设置依赖作业 needs: $TF_NEEDS # 动态注入环境变量 variables: $TF_ENV_VARS # 规则:仅匹配映射中存在的分支 rules: - if: '$TARGET_BRANCH =~ /^(main|staging|dev)$/' before_script: # 用jq从JSON映射中提取当前环境的配置,导出为CI变量 - export RUNNER_TAGS=$(echo "$ENV_MAPPING" | jq -r --arg branch "$TARGET_BRANCH" '.[$branch].runner_tags') - export TF_EXTENDS=$(echo "$ENV_MAPPING" | jq -r --arg branch "$TARGET_BRANCH" '.[$branch].tf_extends') - export TF_NEEDS=$(echo "$ENV_MAPPING" | jq -r --arg branch "$TARGET_BRANCH" '.[$branch].tf_needs') - export TF_ENV_VARS=$(echo "$ENV_MAPPING" | jq -r --arg branch "$TARGET_BRANCH" '.[$branch].tf_env_vars')
方案2:规则分支匹配+!reference引用(兼容低版本GitLab)
如果你的GitLab版本低于14.0(不支持extends使用变量),可以用!reference引用环境专属配置,避免重复代码。
variables: TARGET_BRANCH: "${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-$CI_COMMIT_BRANCH}" # 1. 定义通用Terraform模板 .terraform-base: script: - terraform init - terraform plan - terraform apply -auto-approve artifacts: paths: - terraform.tfstate expire_in: 7d # 2. 定义各环境的专属配置模板 .terraform-prod-config: tags: ["prod-runner"] variables: TF_VAR_ENV: prod TF_WORKSPACE: prod .terraform-staging-config: tags: ["staging-runner"] variables: TF_VAR_ENV: staging TF_WORKSPACE: staging .terraform-dev-config: tags: ["dev-runner"] variables: TF_VAR_ENV: dev TF_WORKSPACE: dev # 3. 单一通用作业,通过规则匹配加载对应配置 terraform-deploy: extends: ".terraform-base" rules: - if: '$TARGET_BRANCH == "main"' needs: ["build-prod"] tags: !reference [.terraform-prod-config, tags] variables: !reference [.terraform-prod-config, variables] - if: '$TARGET_BRANCH == "staging"' needs: ["build-staging"] tags: !reference [.terraform-staging-config, tags] variables: !reference [.terraform-staging-config, variables] - if: '$TARGET_BRANCH == "dev"' needs: ["build-dev"] tags: !reference [.terraform-dev-config, tags] variables: !reference [.terraform-dev-config, variables]
关键注意事项
- 方案1需要作业镜像预装
jq工具(大部分官方Terraform镜像已包含,若没有可在before_script中安装)。 - 确保
needs的数组格式为JSON字符串(如'["build-prod"]'),GitLab CI才能正确解析。 - 若环境模板(如
.terraform-prod)包含专属规则或脚本,extends会自动合并这些配置。
内容的提问来源于stack exchange,提问作者Alex Harvey
相关产品推荐
相关产品推荐

