基于GitLab CI与Terraform实现MR生命周期内的测试环境管理
实现与Merge Request绑定的测试环境生命周期管理
核心思路调整
你之前尝试在MR批准后销毁环境却遇到变量为空的问题,其实更可靠的方案是将销毁时机绑定到MR合并事件——这既贴合你“MR合并后立即销毁”的需求,也避开了批准事件变量的兼容性坑。
分步骤实现方案
以下以GitLab CI为例(其他CI系统逻辑通用,仅需调整规则语法):
1. MR新建时触发Terraform应用(仅执行一次)
利用CI规则匹配MR新建事件,给每个MR的测试环境打上唯一标识(比如MR的IID),确保资源完全隔离:
terraform-apply-test-env: stage: deploy rules: # 仅在MR新建/打开时触发,避免重复执行 - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_STATE == "opened"' allow_failure: false script: # 初始化Terraform,指定与MR绑定的远程状态路径 - terraform init -backend-config="key=tf-state/mr-$CI_MERGE_REQUEST_IID/terraform.tfstate" # 执行计划并应用变更 - terraform plan -out=tfplan -var "mr_id=$CI_MERGE_REQUEST_IID" - terraform apply tfplan variables: # 传入MR ID作为Terraform变量,用于给资源打标签/命名 TF_VAR_mr_id: $CI_MERGE_REQUEST_IID
- 关键要求:必须使用远程状态存储(比如GitLab自带的Terraform State、AWS S3),每个MR对应独立的状态路径,彻底避免状态冲突。
- 幂等性保障:Terraform的apply操作天生幂等,即使意外重复触发,也不会重复创建资源,无需额外做“仅执行一次”的复杂校验。
2. MR合并时触发Terraform销毁
监听MR合并事件,用同一个MR ID定位要销毁的目标资源:
terraform-destroy-test-env: stage: cleanup rules: # 仅在MR合并完成时触发 - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_STATE == "merged"' when: always script: # 初始化时指定对应MR的状态路径 - terraform init -backend-config="key=tf-state/mr-$CI_MERGE_REQUEST_IID/terraform.tfstate" # 自动销毁对应资源 - terraform destroy -auto-approve -var "mr_id=$CI_MERGE_REQUEST_IID" variables: TF_VAR_mr_id: $CI_MERGE_REQUEST_IID
关于$CI_MERGE_REQUEST_APPROUVED变量的问题
这个变量并非在所有MR pipeline中都有效:
- 多数CI系统(比如GitLab)默认只有**专门的“批准触发pipeline”**才会注入该变量,常规的MR pipeline不会包含它。
- 如果你坚持要在批准后销毁,需要在CI设置中开启“当MR被批准时触发pipeline”的规则,同时调整job的触发条件为
if: '$CI_MERGE_REQUEST_APPROVED == "true"'。但从你的需求来看,合并后销毁更贴合业务逻辑,也更可靠。
额外注意事项
- 权限配置:确保CI runner拥有创建/销毁云资源、访问远程状态存储的完整权限。
- 资源标识:在Terraform代码中,用
var.mr_id给所有资源命名或打标签(比如resource "aws_instance" "test" { tags = { MR_ID = var.mr_id } }),方便后续排查和手动清理(如果CI销毁失败)。 - 失败重试:可以给destroy job添加重试机制,避免因临时网络问题导致销毁失败。
内容的提问来源于stack exchange,提问作者Mahdi Electro
相关产品推荐
相关产品推荐

