使用Terraform实现Azure PostgreSQL灵活服务器时间点恢复遇资源冲突问题
问题背景
我通过Terraform部署了Azure PostgreSQL灵活服务器,相关资源定义在子模块./modules/postgreSQL中,该模块会创建azurerm_postgresql_flexible_server和多个azurerm_postgresql_flexible_server_database资源。主配置文件main.tf中引用子模块的方式如下:
module "postgresql" { source = "./modules/postgreSQL" pg_name = "${var.pg_name}" private_dns_zone = "${var.pg_private_dns_zone}" location = data.azurerm_resource_group.resource_group.location resource_group_name = data.azurerm_resource_group.resource_group.name ... ... }
为了通过时点恢复创建新服务器,我尝试两次导入同一子模块并配置不同参数:
module "postgresql" { source = "./modules/postgreSQL" pg_name = "${var.pg_name}" private_dns_zone = "${var.pg_private_dns_zone}" location = data.azurerm_resource_group.resource_group.location resource_group_name = data.azurerm_resource_group.resource_group.name ... ... } # 新恢复的数据库服务器 module "postgresql_new" { source = "./modules/postgreSQL" pg_name = "new${var.pg_name}" private_dns_zone = "new${var.pg_private_dns_zone}" location = data.azurerm_resource_group.resource_group.location resource_group_name = data.azurerm_resource_group.resource_group.name ... ... point_in_time_restore_time_in_utc = "2024-09-22T11:53:37.249000Z" source_server_id = module.postgresql.pg_id create_mode = "PointInTimeRestore" }
执行terraform apply时失败,报错显示Azure在时点恢复过程中已自动创建数据库,Terraform尝试创建同名资源导致冲突:
Error: A resource with the ID "/subscriptions/xxxxx/resourceGroups/rgr-zzzz-dev/providers/Microsoft.DBforPostgreSQL/flexibleServers/yyyyy/databases/mydb"
already exists - to be managed via Terraform this resource needs to be imported into the State.
Please see the resource documentation for "azurerm_postgresql_flexible_server_database" for more information.
解决方案
方法1:修改子模块,条件创建数据库资源
在子模块中添加变量控制是否创建数据库,当create_mode为PointInTimeRestore时跳过数据库资源创建——因为时点恢复会自动复制原服务器的所有数据库。
- 在子模块的
variables.tf中新增控制变量:
variable "create_databases" { type = bool default = true description = "是否创建数据库资源,时点恢复场景设为false" }
- 修改子模块中
azurerm_postgresql_flexible_server_database资源的定义,添加count条件:
resource "azurerm_postgresql_flexible_server_database" "example" { count = var.create_databases ? 1 : 0 name = "mydb" server_id = azurerm_postgresql_flexible_server.example.id charset = "UTF8" collation = "en_US.UTF8" }
- 在主配置中引用恢复服务器的子模块时,设置
create_databases = false:
module "postgresql_new" { source = "./modules/postgreSQL" pg_name = "new${var.pg_name}" private_dns_zone = "new${var.pg_private_dns_zone}" location = data.azurerm_resource_group.resource_group.location resource_group_name = data.azurerm_resource_group.resource_group.name ... ... point_in_time_restore_time_in_utc = "2024-09-22T11:53:37.249000Z" source_server_id = module.postgresql.pg_id create_mode = "PointInTimeRestore" create_databases = false # 新增参数,跳过数据库创建 }
方法2:将Azure自动创建的数据库导入Terraform状态
如果不想修改子模块,可以先手动将已存在的数据库导入Terraform状态,再执行terraform apply:
执行导入命令(替换占位符为实际资源信息,注意子模块中数据库资源的名称要与命令中的标识符一致):
terraform import module.postgresql_new.azurerm_postgresql_flexible_server_database.example /subscriptions/xxxxx/resourceGroups/rgr-zzzz-dev/providers/Microsoft.DBforPostgreSQL/flexibleServers/yyyyy/databases/mydb
导入完成后再次执行terraform apply,Terraform会将已存在的数据库纳入状态管理,不会重复创建。
方法3:单独定义恢复服务器资源,不复用子模块
如果子模块结构复杂,可直接在主配置中单独定义时点恢复的服务器资源,避免数据库资源的重复定义:
resource "azurerm_postgresql_flexible_server" "restored" { name = "new${var.pg_name}" resource_group_name = data.azurerm_resource_group.resource_group.name location = data.azurerm_resource_group.resource_group.location version = "13" # 与源服务器版本保持一致 administrator_login = var.pg_admin_login # 可沿用原账号或设置新账号 administrator_password = var.pg_admin_password sku_name = "GP_Standard_D2s_v3" # 与源服务器SKU保持一致 create_mode = "PointInTimeRestore" source_server_id = module.postgresql.pg_id point_in_time_restore_time_in_utc = "2024-09-22T11:53:37.249000Z" # 其他网络、存储等配置与源服务器保持一致 private_dns_zone_id = azurerm_private_dns_zone.new_zone.id ... }
这种方式下无需额外定义数据库资源,时点恢复会自动复制原服务器的所有数据库。
内容的提问来源于stack exchange,提问作者Fabry

