Terraform 0.12.13,Azurerm提供程序1.35
某些背景:我有一组Azure App Services,它们托管在Azure位置的资源组中的App Service计划中。现在,我需要在另一个Azure位置中复制此堆栈,并添加一些其他资源(例如流量管理器和CNAME,等等)以实现高可用性。从体系结构上讲,我们具有主资源,然后在辅助区域中拥有较小的辅助资源子集(并非所有内容都需要重复)。并非每个部署都需要高可用性,因此我需要能够在运行时实例化或不实例化Secondaries。
因为我想成为一名优秀的软件工程师,所以我创建了一些模块来实例化大部分内容-一个用于应用程序服务,一个用于应用程序服务计划,一个用于流量管理器,等等。
我现在遇到的问题是,我正在使用旧的count +三元运算符把戏来控制是否创建了辅助资源,并且这样做很麻烦,因为1)尚未将count用作模块元参数,并且2)我不知道如何将导出的属性从计数元参数控制的资源传递到模块作为输入变量。
以下代码可以使这一点更加清楚。
resource "azurerm_resource_group" "appservices_secondary" {
name = "foo-services-ca-${local.secondary_release_stage_name}-${var.pipeline}-rg"
location = local.secondary_location
count = var.enable_high_availability ? 1 : 0
}
# Create the app service plan to host the secondary app services
module "plan_secondary" {
source = "./app_service_plan"
release_stage_name = local.secondary_release_stage_name
# HERE'S THE PROBLEMATIC LINE
appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name
location = local.secondary_location
pipeline = var.pipeline
}
如果count解析为1(var.enable_high_availability = true
),则一切正常。
如果计数解析为0(var.enable_high_availability = false
),则terraform plan
失败:
Error: Invalid index
on .terraform\modules\services\secondary.tf line 25, in module "plan_secondary":
25: appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name
|----------------
| azurerm_resource_group.appservices_secondary is empty tuple
The given key does not identify an element in this collection value.
如果我将输入变量值更改为azurerm_resource_group.appservices_secondary.name
,那么它将不会通过terraform validate
,因为它会识别出需要[count.index]
。
是否有解决此问题的简单方法?我越来越多地认为这是一个设计问题,我应该使用count = [1..2]构建模块,而不是用count = 1(主要)和count = [0 ||]构建模块。 1](第二),但这需要我重写所有模块,如果有一些巧妙的解决方法,我想避免这种情况。
答案 0 :(得分:1)
为了解决此问题,您可以为appsvc_resource_group_name
使用条件表达式,以提供一些azurerm_resource_group.appservices_secondary
资源具有count = 0
时要使用的替代值:
appsvc_resource_group_name = length(azurerm_resource_group.appservices_secondary) > 0 ? azurerm_resource_group.appservices_secondary[0].name : "default-value"
该其他模块在禁用高可用性的情况下似乎没有用。在这种情况下,您可能希望将变量定义为可选变量,默认值为null
,以便可以识别模块中未设置的变量:
variable "appsvc_resource_group_name" {
type = string
default = null
}
在配置的其他位置,您可以测试var.appsvc_resource_group_name != null
以查看其是否已启用。
在遵循the module composition patterns时,我可能会使用以下两种策略之一将其构建为两个模块:
这是其中第二种方法的一个例子,只是为了说明我的意思:
module "primary_example" {
source = "./primary_example"
# whatever arguments are needed
}
module "secondary_example" {
source = "./secondary_example"
# Make sure the primary module exports as outputs all of the
# values required to extend to HA mode, and then just pass
# that whole object through to secondary.
primary = module.primary_example
}
在不需要HA模式的配置中,您可以省略module "secondary_example"
。
模块组成模式是将配置分解成描述一个独立功能的小块,然后让根模块从那些功能中选择任何相关的子集,然后以适当的方式进行连接。
在这种情况下,我将非HA基础结构视为一种功能,然后将对该基础结构的HA扩展视为第二项功能(取决于第一项功能),以依赖关系反转样式将它们连接在一起,以便HA扩展可以假定已经存在非HA部署,并且有关它的信息将由其调用方传递。