VSTS发布定义中ARM模板部署:仅创建不存在的Azure资源
针对你遇到的这两个头疼的问题——部署时不想更新已存在的Function App,又怕手动添加的应用设置被覆盖,我给你整理了具体的解决方案:
一、仅在资源不存在时创建Function App
ARM模板默认的Incremental部署模式不会删除现有资源,但会更新模板中定义的资源属性。如果想要完全跳过已存在的资源(不做任何更新操作),可以在模板里给Function App资源添加condition判断,检查该资源是否已经存在于资源组中:
- 先在模板的
parameters部分定义Function App的名称参数: - 在Function App的资源块里,添加
condition属性,用resourceId函数尝试获取资源ID,如果返回空则说明资源不存在,才执行创建逻辑:
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "functionAppName": { "type": "string", "metadata": { "description": "Name of your Azure Function App" } }, // 其他必要参数比如存储账户、宿主计划名称等... }, "resources": [ { "type": "Microsoft.Web/sites", "apiVersion": "2022-03-01", "name": "[parameters('functionAppName')]", // 核心判断:资源不存在才创建 "condition": "[empty(resourceId('Microsoft.Web/sites', parameters('functionAppName')))]", "location": "[resourceGroup().location]", "properties": { "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]", "siteConfig": { "appSettings": [] } // 其他基础配置... }, "dependsOn": [ "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]" ] } ] }
这样部署时,如果资源组里已经有同名的Function App,这个资源块会直接被跳过,不会做任何修改。另外提一句:你现在用的New-AzureRMResourceGroupDeployment已经被弃用了,建议换成Az模块的New-AzResourceGroupDeployment命令,后续兼容性更好。
二、保留手动添加的应用设置
默认情况下,ARM模板里定义的appSettings会完全覆盖现有配置,导致你手动加的密钥丢失。要解决这个问题,我们可以用ARM的list函数获取现有应用设置,再和模板里的配置合并:
在Function App的嵌套config/appsettings资源块里,修改properties为合并后的结果:
{ "type": "Microsoft.Web/sites/config", "apiVersion": "2022-03-01", "name": "[concat(parameters('functionAppName'), '/appsettings')]", "dependsOn": [ "[resourceId('Microsoft.Web/sites', parameters('functionAppName'))]" ], "properties": "[union(list(concat(resourceId('Microsoft.Web/sites', parameters('functionAppName')), '/config/appsettings'), '2022-03-01').properties, variables('defaultAppSettings'))]" }
这里的逻辑是:
list(...):获取Function App当前已有的所有应用设置variables('defaultAppSettings'):你在模板里定义的默认配置(比如必须的连接字符串、环境变量)union():合并两个对象,重复的键会用模板里的值覆盖现有值,手动添加的非重复键则会被保留
不过要注意,第一次部署时资源还不存在,list函数会报错,所以可以结合前面的condition用if函数做判断:
"properties": "[if(empty(resourceId('Microsoft.Web/sites', parameters('functionAppName'))), variables('defaultAppSettings'), union(list(concat(resourceId('Microsoft.Web/sites', parameters('functionAppName')), '/config/appsettings'), '2022-03-01').properties, variables('defaultAppSettings')))]"
这样第一次部署时直接用模板里的默认设置,后续部署就会合并现有配置和模板配置,手动加的密钥再也不会丢了。
额外小提示
在Azure DevOps(原VSTS)的发布管道里,ARM模板部署任务默认用的就是Incremental模式,千万别改成Complete模式,否则会删除模板里没定义的资源,那麻烦就大了。
内容的提问来源于stack exchange,提问作者Mandar Jogalekar

