使用Terraform时如何避免覆盖GitLab CI变量
解决Terraform部署GitLab项目时重复重置VAPID密钥的问题
问题场景
用Terraform部署GitLab项目时,每次运行都会重新生成VAPID密钥并覆盖GitLab CI变量,希望实现仅在变量不存在时才创建密钥和变量,避免每次运行重置密钥。
原配置中,external数据源每次执行都会生成新密钥,导致资源每次都更新,现在需要调整逻辑:
解决方案
核心是先通过gitlab_project_variable数据源检查目标变量是否已存在,仅当变量不存在时才生成密钥并创建变量。
修改后的完整配置
variable "env_scopes_all" { type = list(object({ scope = string env_type = string })) default = [ { scope = "prod/live", env_type = "live" }, { scope = "prod/staging", env_type = "staging" }, { scope = "prod/review-*", env_type = "review" } ] } # 检查每个环境下的VAPID_PRIVATE_KEY是否已存在 data "gitlab_project_variable" "existing_vapid_private_keys" { count = length(var.env_scopes_all) project = gitlab_project.elybird.id key = "VAPID_PRIVATE_KEY" environment_scope = var.env_scopes_all[count.index].scope # 变量不存在时不报错,返回空结果 lifecycle { ignore_changes = all } } # 仅当对应环境的VAPID_PRIVATE_KEY不存在时,生成新的VAPID密钥 data "external" "vapid_keys" { count = length([ for i, scope in var.env_scopes_all : scope if data.gitlab_project_variable.existing_vapid_private_keys[i].id == "" ]) program = ["/bin/sh", "-c", <<-EOF pem=$(openssl ecparam -name prime256v1 -genkey -noout) private_key=$(echo "$pem" | openssl ec -outform DER 2>/dev/null | tail -c +8 | head -c 32 | base64 -w 0 | tr -d '=' | tr '/+' '_-') public_key=$(echo "$pem" | openssl ec -pubout -outform DER 2>/dev/null | tail -c 65 | base64 -w 0 | tr -d '=' | tr '/+' '_-') printf '{"private_key":"%s","public_key":"%s"}\n' "$private_key" "$public_key" EOF ] } # 仅当对应环境的VAPID_PRIVATE_KEY不存在时,创建私有密钥变量 resource "gitlab_project_variable" "VAPID_PRIVATE_KEY" { count = length(data.external.vapid_keys) project = gitlab_project.elybird.id key = "VAPID_PRIVATE_KEY" value = data.external.vapid_keys[count.index].result.private_key description = "Base64-encoded VAPID private key for push notifications" environment_scope = var.env_scopes_all[count.index].scope masked = false protected = false raw = true variable_type = "env_var" } # 仅当对应环境的VAPID_PRIVATE_KEY不存在时,创建公开密钥变量 resource "gitlab_project_variable" "VAPID_PUBLIC_KEY" { count = length(data.external.vapid_keys) project = gitlab_project.elybird.id key = "VAPID_PUBLIC_KEY" value = data.external.vapid_keys[count.index].result.public_key description = "Base64-encoded VAPID public key for client push subscription" environment_scope = var.env_scopes_all[count.index].scope masked = false protected = false raw = true variable_type = "env_var" }
关键逻辑说明
- 检查变量存在性:
data.gitlab_project_variable.existing_vapid_private_keys遍历每个环境scope,检查对应的私有密钥变量是否存在。如果变量不存在,id字段会为空。 - 条件生成密钥:
data.external.vapid_keys的count通过列表推导式筛选出变量不存在的环境,只对这些环境生成新密钥,避免重复生成。 - 条件创建变量:资源的
count和external数据源的长度保持一致,只在需要的环境下创建变量,已存在的环境不会执行创建逻辑。
额外注意事项
- 如果后续需要重置某个环境的密钥,只需手动删除GitLab中对应的CI变量,下次运行Terraform时会自动重新生成并创建。
- 确保Terraform使用的GitLab token具备
api权限,能正常读取项目变量。
内容的提问来源于stack exchange,提问作者JT2809
相关产品推荐
相关产品推荐

