You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Terraform批量创建Azure Databricks作业的状态管理问题求助

解决Terraform循环部署Databricks作业时的状态销毁问题

问题根源

你当前的做法是在同一个Terraform工作目录下,循环执行terraform apply并传入不同的job_file_dir_path参数。由于Terraform的状态文件(默认是terraform.tfstate)会跟踪当前配置中的所有资源,每次循环时,新的配置只包含当前job_file_dir_path对应的资源,Terraform会认为之前迭代创建的资源已经从配置中移除,因此会销毁这些旧资源,最终只保留最后一次迭代的资源。

解决方案

方案1:重构Terraform代码,一次性管理所有作业(推荐)

直接让Terraform遍历所有作业目录,一次性创建所有资源,避免循环调用apply。这种方法是Terraform的最佳实践,所有资源都在同一个状态文件中管理,不会出现资源被误销毁的情况。

步骤:

  1. 创建作业模块
    将现有的作业部署代码(包括workspace_file.tf、Databricks作业定义等)封装为一个Terraform模块,比如在terraform/modules/job目录下存放这些代码,并暴露必要的变量:

    # terraform/modules/job/variables.tf
    variable "artifactory_user" {
      type = string
    }
    
    variable "artifactory_api_key" {
      type = string
    }
    
    variable "project_name" {
      type = string
    }
    
    variable "job_file_dir_path" {
      type = string
    }
    

    调整模块内的workspace_file.tf,用目录名作为作业名称(确保资源路径唯一):

    # terraform/modules/job/workspace_file.tf
    resource "databricks_workspace_file" "workspace_file" {
      for_each = fileset(var.job_file_dir_path, "*.py")
      source   = "${var.job_file_dir_path}/${each.value}"
      path     = "/Shared/job_files/${var.project_name}/${basename(var.job_file_dir_path)}/${each.value}"
    }
    
    # 此处添加Databricks作业/流水线的资源定义,同样使用basename(var.job_file_dir_path)作为作业标识
    
  2. 根模块调用作业模块
    在根目录的Terraform代码中,遍历所有作业目录并调用模块:

    # terraform/main.tf
    variable "artifactory_user" {
      type = string
    }
    
    variable "artifactory_api_key" {
      type = string
    }
    
    variable "project_name" {
      type = string
      default = "project"
    }
    
    # 自动获取所有作业目录
    locals {
      job_dirs = [for d in fileset("../databricks/jobs", "*") : "../databricks/jobs/${d}"]
    }
    
    # 为每个作业目录创建一个模块实例
    module "databricks_job" {
      for_each             = toset(local.job_dirs)
      source               = "./modules/job"
      artifactory_user     = var.artifactory_user
      artifactory_api_key  = var.artifactory_api_key
      project_name         = var.project_name
      job_file_dir_path    = each.value
    }
    
  3. 执行部署
    不再需要Bash循环,直接执行一次apply即可:

    terraform apply -var artifactory_user=$ARTIFACTORY_USER \
                    -var artifactory_api_key=$ARTIFACTORY_API_KEY
    

方案2:使用Terraform工作区隔离状态

为每个作业创建独立的Terraform工作区,每个工作区有自己的状态文件,避免互相干扰。

修改Bash脚本:

for job_file_dir_path in ../databricks/jobs/* ; do
    # 从目录路径提取作业名称
    job_name=$(basename "$job_file_dir_path")
    # 切换到对应工作区,不存在则创建
    terraform workspace select "$job_name" || terraform workspace new "$job_name"
    # 执行部署
    terraform apply -var artifactory_user=$ARTIFACTORY_USER \
                  -var artifactory_api_key=$ARTIFACTORY_API_KEY \
                  -var project_name=project \
                  -var job_file_dir_path=$job_file_dir_path \
                  -auto-approve
done

工作区的状态文件会存储在terraform.tfstate.d/${job_name}目录下,每个作业的状态相互独立,不会出现资源被销毁的问题。

方案3:使用独立状态文件

每次执行apply时指定不同的状态文件路径,手动隔离状态。

修改Bash脚本:

# 创建状态文件存储目录
mkdir -p terraform_states

for job_file_dir_path in ../databricks/jobs/* ; do
    job_name=$(basename "$job_file_dir_path")
    # 指定状态文件路径
    terraform apply -state=./terraform_states/${job_name}.tfstate \
                  -var artifactory_user=$ARTIFACTORY_USER \
                  -var artifactory_api_key=$ARTIFACTORY_API_KEY \
                  -var project_name=project \
                  -var job_file_dir_path=$job_file_dir_path \
                  -auto-approve
done

这种方法需要手动管理状态文件的存储和备份,适合临时场景或简单需求。

总结

  • 方案1是长期维护的最佳选择,代码结构更清晰,便于统一管理所有资源。
  • 方案2适合对现有代码改动最小的场景,利用Terraform内置的工作区机制隔离状态。
  • 方案3适合临时测试或简单场景,但状态文件的管理成本较高。

内容的提问来源于stack exchange,提问作者Baha Abrougui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:23:28