使用Terraform批量创建Azure Databricks作业的状态管理问题求助
问题根源
你当前的做法是在同一个Terraform工作目录下,循环执行terraform apply并传入不同的job_file_dir_path参数。由于Terraform的状态文件(默认是terraform.tfstate)会跟踪当前配置中的所有资源,每次循环时,新的配置只包含当前job_file_dir_path对应的资源,Terraform会认为之前迭代创建的资源已经从配置中移除,因此会销毁这些旧资源,最终只保留最后一次迭代的资源。
解决方案
方案1:重构Terraform代码,一次性管理所有作业(推荐)
直接让Terraform遍历所有作业目录,一次性创建所有资源,避免循环调用apply。这种方法是Terraform的最佳实践,所有资源都在同一个状态文件中管理,不会出现资源被误销毁的情况。
步骤:
创建作业模块
将现有的作业部署代码(包括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)作为作业标识根模块调用作业模块
在根目录的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 }执行部署
不再需要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

