合并至master分支后GitLab CI/CD作业找不到Terraform计划工件失败
问题:GitLab CI/CD部署作业无法找到Terraform Plan生成的工件
问题背景
我维护一套GitLab CI/CD流水线,核心作业逻辑如下:
terraform_plan_configuration:执行terraform plan并生成deployment_plan工件,仅在创建目标为master分支的合并请求(MR)时触发,工件保留20分钟。deploy_terraform_infrastructure:执行terraform apply deployment_plan部署资源,仅在代码合并到master分支后运行。
但部署作业始终提示找不到deployment_plan文件,原以为GitLab工件可跨作业访问,实际触发文件不存在的错误。流水线YAML配置如下:
stages: - analysis - plan - deployment - release terraform_validate_configuration: stage: analysis image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" script: - terraform init - terraform validate artifacts: paths: - ./.terraform/ expire_in: "3 mins" checkov_scan_directory: stage: analysis image: name: "bridgecrew/checkov:3.2.344" entrypoint: [""] rules: - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" script: - checkov --directory ./ --soft-fail trivy_scan_security: stage: analysis image: name: "aquasec/trivy:0.58.2" entrypoint: [""] rules: - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" script: - trivy config --format table ./ terraform_plan_configuration: stage: plan image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" dependencies: - terraform_validate_configuration script: - terraform init - terraform plan -out=deployment_plan artifacts: paths: - ./deployment_plan when: on_success expire_in: "20 mins" deploy_terraform_infrastructure: stage: deployment image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: - if: $CI_COMMIT_BRANCH == "master" dependencies: - terraform_plan_configuration - terraform_validate_configuration script: - terraform apply deployment_plan
核心原因
GitLab中合并请求(MR)流水线和分支流水线是完全独立的执行实例,工件无法跨流水线共享:
terraform_plan_configuration运行在MR专属流水线中,生成的deployment_plan仅属于该流水线。deploy_terraform_infrastructure运行在代码合并后的master分支流水线中,无法访问MR流水线的工件。
另外,Terraform的plan输出文件和当前代码状态、后端状态严格绑定,即使手动拷贝也可能因代码或状态变化导致失效,这也是跨流水线复用plan文件的潜在风险。
解决方案
方案1:在部署作业中重新执行Plan并Apply
直接在deploy_terraform_infrastructure中重新生成plan文件,避免跨流水线依赖工件。修改后的作业配置如下:
deploy_terraform_infrastructure: stage: deployment image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: - if: $CI_COMMIT_BRANCH == "master" dependencies: - terraform_validate_configuration script: - terraform init - terraform plan -out=deployment_plan - terraform apply deployment_plan artifacts: paths: - ./deployment_plan expire_in: "20 mins"
优势:无需依赖MR流水线的工件,保证plan和apply使用的是合并后master分支的最新代码和状态,避免状态不一致问题。
方案2:将Plan和Deploy放在同一流水线中
调整触发规则,让terraform_plan_configuration和deploy_terraform_infrastructure在同一条流水线中执行(比如MR合并后的master分支流水线),但需添加保护机制避免误部署:
terraform_plan_configuration: stage: plan image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: # 保留MR触发,同时让master分支流水线也触发 - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" - if: $CI_COMMIT_BRANCH == "master" dependencies: - terraform_validate_configuration script: - terraform init - terraform plan -out=deployment_plan artifacts: paths: - ./deployment_plan when: on_success expire_in: "20 mins" deploy_terraform_infrastructure: stage: deployment image: name: "hashicorp/terraform:1.10" entrypoint: [""] rules: - if: $CI_COMMIT_BRANCH == "master" # 添加手动触发,避免自动部署 when: manual dependencies: - terraform_plan_configuration - terraform_validate_configuration script: - terraform apply deployment_plan
优势:plan和apply在同一流水线中,工件可正常共享;添加when: manual确保部署需要人工确认,降低风险。
内容的提问来源于stack exchange,提问作者Mykoliux




