使用Terraform部署Azure Function App时出现ServiceUnavailable错误及RunFromPackage下载异常问题
看起来你遇到的问题挺典型的——虽然Terraform成功创建了所有资源,但Function App就是加载不了函数,日志里还报了包下载失败,可手动访问URL又完全正常。我帮你梳理几个最可能的原因和对应的修复方案:
1. 核心配置冲突:.NET隔离模式的Worker Runtime设置错误
你在site_config里明确开启了.NET隔离模式(use_dotnet_isolated_runtime = true),但app_settings里的FUNCTIONS_WORKER_RUNTIME却设成了"dotnet",这完全不匹配!
隔离模式的正确Worker Runtime值应该是"dotnet-isolated",这个错误会直接导致函数宿主无法启动对应的worker进程,进而抛出ServiceUnavailable错误,甚至可能连带出现RunFromPackage的日志误导。
修复方法:修改app_settings中的对应配置:
app_settings = { "FUNCTIONS_WORKER_RUNTIME" = "dotnet-isolated" # 改成这个值 "WEBSITE_RUN_FROM_PACKAGE" = "https://${azurerm_storage_account.mtr_storage.name}.blob.core.windows.net/${azurerm_storage_container.mtr_hello_function_container.name}/${azurerm_storage_blob.mtr_hello_function_blob.name}${data.azurerm_storage_account_blob_container_sas.storage_account_blob_container_sas_for_hello.sas}" "AzureWebJobsStorage" = azurerm_storage_account.mtr_storage.primary_connection_string "AzureWebJobsDisableHomepage" = "true" }
2. SAS Token有效期太短,导致函数启动时已过期
你生成的容器SAS Token有效期只有10分钟(start提前5分钟,expiry延后5分钟),Terraform部署过程加上Function App初始化启动的时间很容易超过这个窗口,尤其是第一次部署的时候。等函数宿主真正尝试下载包时,SAS已经失效了——你手动访问的时候可能还在有效期内,但函数启动时已经过期了。
修复方法:大幅延长SAS的有效期,比如设置成24小时甚至更久:
data "azurerm_storage_account_blob_container_sas" "storage_account_blob_container_sas_for_hello" { connection_string = azurerm_storage_account.mtr_storage.primary_connection_string container_name = azurerm_storage_container.mtr_hello_function_container.name start = timeadd(timestamp(), "-5m") expiry = timeadd(timestamp(), "24h") # 改成24小时,避免过期 permissions { read = true add = false create = false write = false delete = false list = false } }
更推荐的长期方案是使用Managed Identity访问存储账户,完全不需要SAS Token,既安全又不会有过期问题:
- 给Function App分配一个系统分配的Managed Identity
- 给这个Identity分配存储账户Blob容器的
Storage Blob Data Reader角色 - 修改
WEBSITE_RUN_FROM_PACKAGE为存储Blob的直接URL(不带SAS):"WEBSITE_RUN_FROM_PACKAGE" = "https://${azurerm_storage_account.mtr_storage.name}.blob.core.windows.net/${azurerm_storage_container.mtr_hello_function_container.name}/${azurerm_storage_blob.mtr_hello_function_blob.name}"
3. 存储账户网络规则阻止了Function App的访问请求
你的存储账户设置了default_action = "Deny",虽然添加了IP规则和子网规则,但Function App运行时的出站IP可能不在你允许的列表里——你手动访问用的是自己本地的IP,但函数宿主的请求来自Azure内部的函数服务IP,这个IP并没有被加入到存储账户的允许列表中。
验证方法:暂时把存储账户的default_action改成"Allow",重新部署后看函数是否能正常加载。如果能,说明是网络规则的问题。
修复方法:
- 找到Function App的出站IP地址(在Azure门户的Function App -> 网络 -> 出站IP地址里查看),把这些IP加入到存储账户的
ip_rules中 - 或者开启存储账户的
Microsoft.Web服务端点,并把Function App所在的虚拟子网加入到存储账户的virtual_network_subnet_ids中(需要确保Function App已加入该子网)
4. 最后检查ZIP包的结构是否符合隔离模式要求
虽然你说包结构正确,但还是要确认:.NET 8隔离模式的Function App包根目录应该包含bin文件夹和host.json,如果是发布生成的包,应该是正确的,但可以解压后再确认一下。
试试上面的方案,尤其是第一个Worker Runtime的配置,大概率能解决你的问题!
备注:内容来源于stack exchange,提问作者Marek M.

