尝试在Terraform脚本上进行计划或应用时出现以下错误。
Error: Invalid count argument
on main.tf line 157, in resource "azurerm_sql_firewall_rule" "sqldatabase_onetimeaccess_firewall_rule":
157: count = length(split(",", azurerm_app_service.app_service.possible_outbound_ip_addresses))
The "count" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the count depends on.
我知道这已经失败了,因为在创建app_service之前,它不知道要创建的防火墙规则的数量。我可以只使用参数apply
运行-target=azurerm_app_service.app_service
,然后在创建app_service之后运行另一个apply。
但是,这对于我们的CI流程不是很好,如果我们想从terraform脚本中创建一个全新的环境,我们只想告诉terraform来构建它,而不必告诉它要构建的每个目标
在terraform中是否有一种方法可以说无需构建目标就可以构建所需的所有东西?
下面还是一个提供上述错误的terraform脚本示例:
provider "azurerm" {
version = "=1.38.0"
}
resource "azurerm_resource_group" "resourcegroup" {
name = "rg-stackoverflow60187000"
location = "West Europe"
}
resource "azurerm_app_service_plan" "service_plan" {
name = "plan-stackoverflow60187000"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = azurerm_resource_group.resourcegroup.location
kind = "Linux"
reserved = true
sku {
tier = "Standard"
size = "S1"
}
}
resource "azurerm_app_service" "app_service" {
name = "app-stackoverflow60187000"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = azurerm_resource_group.resourcegroup.location
app_service_plan_id = azurerm_app_service_plan.service_plan.id
site_config {
always_on = true
app_command_line = ""
linux_fx_version = "DOCKER|nginxdemos/hello"
}
app_settings = {
"WEBSITES_ENABLE_APP_SERVICE_STORAGE" = "false"
}
}
resource "azurerm_sql_server" "sql_server" {
name = "mysqlserver-stackoverflow60187000"
resource_group_name = azurerm_resource_group.resourcegroup.name
location = azurerm_resource_group.resourcegroup.location
version = "12.0"
administrator_login = "4dm1n157r470r"
administrator_login_password = "4-v3ry-53cr37-p455w0rd"
}
resource "azurerm_sql_database" "sqldatabase" {
name = "sqldatabase-stackoverflow60187000"
resource_group_name = azurerm_sql_server.sql_server.resource_group_name
location = azurerm_sql_server.sql_server.location
server_name = azurerm_sql_server.sql_server.name
edition = "Standard"
requested_service_objective_name = "S1"
}
resource "azurerm_sql_firewall_rule" "sqldatabase_firewall_rule" {
name = "App Service Access (${count.index})"
resource_group_name = azurerm_sql_database.sqldatabase.resource_group_name
server_name = azurerm_sql_database.sqldatabase.name
start_ip_address = element(split(",", azurerm_app_service.app_service.possible_outbound_ip_addresses), count.index)
end_ip_address = element(split(",", azurerm_app_service.app_service.possible_outbound_ip_addresses), count.index)
count = length(split(",", azurerm_app_service.app_service.possible_outbound_ip_addresses))
}
答案 0 :(得分:2)
要使此功能不出现错误消息中所述的-target
解决方法,需要使用Terraform仅可从配置中知道的值(而不是提供者在应用时生成的值)来重新构造问题。
然后,诀窍是找出Azure API使用的配置中的哪些值来确定要返回多少IP地址,并依靠那些 。我对Azure不够了解,无法为您提供具体的答案,但是我在Inbound/Outbound IP addresses上看到这似乎是Azure App Services的操作细节,而不是您可以控制的东西,因此很可能会出现此问题无法解决。
如果确实没有办法根据配置来预测possible_outbound_ip_addresses
中有多少个地址,那么另一种方法是将您的配置分为两个部分,一个部分依赖另一个部分。第一个配置您的App Service以及与之一起管理的其他所有内容,然后第二个可能使用the azurerm_app_service
data source来检索有关假定已存在的App Service的数据,并根据该数据制定防火墙规则
无论哪种方式,您都需要运行Terraform两次以使必要的数据可用。使用-target
的优点是,您在初始引导过程中只需要执行一次有趣的工作流,因此您有可能可以在CI外部进行初始创建以获取最初创建的对象,然后使用CI进行正在进行的更改。只要不替换应用程序服务对象,后续的Terraform计划就已经知道设置了多少个IP地址,因此应该能够正常完成。