Terraform数据源“archive_file”即使设置了depends_on,在计划阶段仍会对source_dir进行求值

前端开发 2026-07-10

环境:Terraform 1.14,archive provider 2.7.1

我在Terraform中有一个用于打包Lambda的流水线,流程如下:

  1. null_resource运行一个local-exec provisioner,将Python依赖安装到构建目录
  2. 一个wait-gate null_resource验证构建已完成(基于文件的握手)
  3. data "archive_file" 将构建目录打包成ZIP,并对wait gate设置依赖(depends_on)
  4. 通过local_existing_package将 ZIP路径传递给terraform-aws-modules/lambda
  resource "null_resource" "build_lambda" {
    triggers = {
      source_hash = local.source_hash
    }

    provisioner "local-exec" {
      interpreter = ["/bin/bash", "-euo", "pipefail", "-c"]
      command     = <<-EOT
        rm -rf "${local.build_dir}"
        mkdir -p "${local.build_dir}"
        pip3 install requests -t "${local.build_dir}" --quiet
        cp "${var.source_dir}/handler.py" "${local.build_dir}/"
        date -u > "${local.build_dir}/.build_complete"
      EOT
    }
  }
  resource "null_resource" "wait_for_build" {
    triggers = {
      build_id = null_resource.build_lambda.id
    }

    provisioner "local-exec" {
      interpreter = ["/bin/bash", "-euo", "pipefail", "-c"]
      command     = <<-EOT
        if [[ ! -f "${local.build_dir}/.build_complete" ]]; then
          echo "Error: build not complete" >&2
          exit 1
        fi
        echo "Build verified"
      EOT
    }
  }

  data "archive_file" "lambda_package" {
    type        = "zip"
    source_dir  = local.build_dir
    output_path = local.zip_path

    depends_on = [null_resource.wait_for_build]
  }

  module "lambda" {
    source  = "terraform-aws-modules/lambda/aws"
    version = "~> 7.0"

    create_package         = false
    local_existing_package = data.archive_file.lambda_package.output_path
    # ...
  }

问题出现在一个干净的CI工作区(Bitbucket Pipelines,之前没有状态文件,也没有.build/ 目录),执行terraform apply时失败,错误信息为:

Archive creation error with   
  module.lambda_module.data.archive_file.lambda_package

  error creating archive: error archiving directory: could not archive
  missing directory: /opt/atlassian/pipelines/agent/build/.build/lambda-package

我已经尝试了:

  • data "archive_file" 并带有depends_on → 失败(计划阶段目录缺失)
  • resource "archive_file" 并带有depends_on → 失败,所有哈希属性返回了 "Provider returned invalid result object after apply"
  • 使用基于文件的握手的null_resource wait gate提供程序 → 同样失败
  • 使用terraform_data代替null_resource → 同样失败

请指出原因并给出可行的修复思路。

解决方案

Terraform并非为这类 "先构建再部署" 的工作流而设计。

来自 hashicorp/archivearchive_file 数据源确实实现了这类工作流的一部分,但它的实现方式在本质上存在缺陷,因为Terraform期望数据源在计划阶段仅读取已经存在的信息,而不是创建新对象(磁盘上的文件)或直接对apply阶段生成的对象作出反应。archive_file 是对Terraform提供程序协议的错误实现,因此很难以可靠的方式使用它。

相反,我建议把Terraform仅用于此流水线的 “部署” 部分,并在Terraform之外解决构建部分,使用一个更合适的工具来根据源代码构建发布工件。

组装这样一条流水线有多种做法,但有一种可行的方法是,在AWS SSM Parameter Store中存放包含当前源代码版本的S3对象的名称,然后在你的Terraform配置中使用 aws_ssm_parameter 来获取它:

data "aws_ssm_parameter" "current_version" {
  name = "current_lambda_package"
}

resource "aws_lambda_function" "example" {
  s3_bucket = "example_lambda_packages"
  s3_key    = data.aws_ssm_parameter.current_version.value
}

之后,你可以让流水线的单独 build 步骤把构建好的包写入Amazon S3,然后更新 current_lambda_package 参数以指向它。

除了避免在Terraform内直接解决时出现的排序问题外,还有一个二级好处:如果在部署过程中或之后发现新版本有缺陷,你可以把 current_lambda_package 重置回之前的值,并再次运行 terraform apply 以回退到你之前正在运行的已知良好包。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章