使用幂等 ARM 模板将两个 Azure 应用服务部署到同一个应用服务计划
Deploy two Azure App Services to the same App Service Plan using idempotent ARM TEMPLATE
问题
如何在使用 VSTS 幂等持续集成/持续部署过程时将两个不同的 Azure 应用服务部署到同一个应用服务计划。
环境
我写了两个 ARM TEMPLATES
,每个都将 Web 应用程序部署到 Azure App Service。
为了部署应用服务,必须先创建服务计划。
ARM TEMPLATES
目前为每个 Web 应用创建了一个唯一的服务计划。
我正在使用 VSTS 发布定义在每个成功的 VSTS 构建上进行部署。即发布被设计为幂等的。
目前每个网络应用程序都有自己的资源组,其中包括自己的应用程序服务计划。理想情况下,每个 Web 应用程序都有自己的资源组,但是应用服务计划可以在自己的资源组中(如果可能的话)。
下面的模板是用于将 Web 应用服务部署到应用服务计划的模板之一。
它显示了使用命名转换创建应用服务计划:
appname-Plan-q2dkkaaaaaaaa
这是使用以下方法创建的:
- 在 ARM 参数文件中定义的七个字符标识符 "appname"。
- 资源标识符"plan"。
- 资源组名称,来自创建时随机命名的存储帐户名称"q2dkkaaaaaaaa"。
即
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
示例
{
"parameters": {
"appName": {
"type": "string",
"maxLength": 7,
"metadata": {
"description": "The name of the app that you wish to create."
}
},
"appServicePlanSku": {
"type": "string",
"defaultValue": "Standard",
"metadata": {
"description": "The Service Plan SKU"
}
},
"appServicePlanWorkerSize": {
"type": "string",
"defaultValue": "0",
"metadata": {
"description": "The App Service Plan Worker Size (?)"
}
},
"appServicePlanSkuCode": {
"type": "string",
"defaultValue": "S1",
"metadata": {
"description": "The App Service Plan SKU Code"
}
},
"appServicePlanNumWorkers": {
"type": "string",
"defaultValue": "2",
"metadata": {
"description": "The Number of App Service Workers."
}
},
"variables": {
"webAppName": "[concat(parameters('appName'),'-wa-', uniqueString(resourceGroup().id))]",
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
"stageSlotName": "stageSlot",
"devSlotName": "devSlot"
}
},
"resources": [
{
"apiVersion": "2016-09-01",
"name": "[variables('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('hostingPlanName')]",
"workerSizeId": "[parameters('appServicePlanWorkerSize')]",
"numberOfWorkers": "[parameters('appServicePlanNumWorkers')]"
},
"sku": {
"Tier": "[parameters('appServicePlanSku')]",
"Name": "[parameters('appServicePlanSkuCode')]"
},
"dependsOn": []
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"location": "[resourceGroup().location]",
"kind": "webapp",
"tags": {
"Environment": "production",
"displayName": "WebAppService"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
],
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms',variables('hostingPlanName'))]"
},
"resources": [
{
"name": "slotConfigNames",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"
],
"tags": {
"displayName": "slotConfigNames"
},
"properties": {
"appSettingNames": []
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('stageSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
},
{
"apiVersion": "2015-08-01",
"name": "[variables('devSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
}
]
}
]
}
问题
我正在尝试执行两个 ARM 模板(类似于上面的示例)以将两个不同的 Web 应用程序部署到同一个服务计划。
很明显,这两个 Web 应用程序必须调用相同的中央资源,以确保它们都部署到相同的应用程序服务资源名称并执行任何更改。
- 如果应用服务计划存在 = 部署网络应用。
- 如果应用服务计划不存在 = 创建服务计划然后部署网络应用程序。
- 如果应用服务计划已更改 = 部署服务计划更改(例如层更改),然后部署 Web 应用程序。
考虑到上面的环境描述,我有什么选择才能让它工作?
- 可能是发布定义中的 VSTS 全局参数?
- ARM 模板调用创建应用服务计划的 PowerShell 脚本?
热衷于遵循最佳实践。
我希望上面的描述足够详细。抱歉,如果遗漏了什么。谢谢。
ARM模板默认支持您的需求。基本上,如果 ARM 模板遇到存在的资源,如果属性不匹配,它将更新资源。否则它将使用您在 ARM 模板中设置的属性创建资源。
解决方案
我的解决方案是创建三个模板:
- 用于创建应用服务计划的模板 1。此 ARM 模板存储在 BLOB 容器中,发布管道可通过 SAS URI 访问。
- 用于创建网络应用程序 A 的模板 2。此模板使用 LINKED TEMPLATE 功能来调用和执行共享模板。
- 用于创建网络应用程序 B 的模板 3。此模板使用 LINKED TEMPLATE 功能来调用和执行共享模板。
结果
- 然后两个网络应用程序都发布到同一个服务器场,共享
实例。
- 部署的幂等性得以保持。
- 任何应用服务计划部署和任何修正的单一事实。
- 所需服务器场数量节省的资金。
示例
共享服务计划 - 共享服务计划的 ARM 模板示例:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"planLabel": {
"defaultValue": "shared-service-plan",
"type": "string"
}
},
"variables": {
"servicePlanName": "[concat(parameters('planLabel'),'-Plan-', uniqueString(resourceGroup().id))]"
},
"resources": [
{
"comments": "Creates an App Service Plan on the Standard (S1) SKU.",
"type": "Microsoft.Web/serverfarms",
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 2
},
"kind": "app",
"name": "[variables('servicePlanName')]",
"apiVersion": "2016-09-01",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('servicePlanName')]"
},
"dependsOn": []
}
],
"outputs": {
"servicePlanResourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
},
"servicePlanName":{
"type": "string",
"value": "[variables('servicePlanName')]"
},
"resourceGroupName":{
"type": "string",
"value": "[resourceGroup().name]"
}
}
}
Web 应用程序 A - 包含链接模板的 ARM 模板示例:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"servicePlanLabel": {
"type": "string",
"metadata": {
"description": "The base name for the App Service Plan to be used in the linked template."
},
"defaultValue": "plan"
},
"appServicePlanResourceGroup": {
"type": "string",
"metadata": {
"Description": "The name of the Resource Group the shared App Service Plan will be deployed to."
},
"defaultValue": "group"
},
"appServicePlanTemplateUri": {
"type": "string",
"metadata": {
"description": "The URI to the App Service Plan linked template in BLOB"
}
}
},
"variables": {},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "appServicePlanTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('appServicePlanResourceGroup')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[parameters('appServicePlanTemplateUri')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"planLabel": {
"value": "[parameters('servicePlanLabel')]"
}
}
}
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"location": "[resourceGroup().location]",
"kind": "webapp",
"tags": {
"Environment": "production",
"displayName": "App"
},
"dependsOn": [
"[resourceId(parameters('appServicePlanResourceGroup'), 'Microsoft.Resources/deployments', 'appServicePlanTemplate')]"
],
"properties": {}
}
}
}
希望这对某人有用。
谢谢
斯科特
问题
如何在使用 VSTS 幂等持续集成/持续部署过程时将两个不同的 Azure 应用服务部署到同一个应用服务计划。
环境
我写了两个
ARM TEMPLATES
,每个都将 Web 应用程序部署到 Azure App Service。为了部署应用服务,必须先创建服务计划。
ARM TEMPLATES
目前为每个 Web 应用创建了一个唯一的服务计划。我正在使用 VSTS 发布定义在每个成功的 VSTS 构建上进行部署。即发布被设计为幂等的。
目前每个网络应用程序都有自己的资源组,其中包括自己的应用程序服务计划。理想情况下,每个 Web 应用程序都有自己的资源组,但是应用服务计划可以在自己的资源组中(如果可能的话)。
下面的模板是用于将 Web 应用服务部署到应用服务计划的模板之一。
它显示了使用命名转换创建应用服务计划:
appname-Plan-q2dkkaaaaaaaa
这是使用以下方法创建的:
- 在 ARM 参数文件中定义的七个字符标识符 "appname"。
- 资源标识符"plan"。
- 资源组名称,来自创建时随机命名的存储帐户名称"q2dkkaaaaaaaa"。
即
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
示例
{
"parameters": {
"appName": {
"type": "string",
"maxLength": 7,
"metadata": {
"description": "The name of the app that you wish to create."
}
},
"appServicePlanSku": {
"type": "string",
"defaultValue": "Standard",
"metadata": {
"description": "The Service Plan SKU"
}
},
"appServicePlanWorkerSize": {
"type": "string",
"defaultValue": "0",
"metadata": {
"description": "The App Service Plan Worker Size (?)"
}
},
"appServicePlanSkuCode": {
"type": "string",
"defaultValue": "S1",
"metadata": {
"description": "The App Service Plan SKU Code"
}
},
"appServicePlanNumWorkers": {
"type": "string",
"defaultValue": "2",
"metadata": {
"description": "The Number of App Service Workers."
}
},
"variables": {
"webAppName": "[concat(parameters('appName'),'-wa-', uniqueString(resourceGroup().id))]",
"hostingPlanName": "[concat(parameters('appName'),'-Plan-', uniqueString(resourceGroup().id))]",
"stageSlotName": "stageSlot",
"devSlotName": "devSlot"
}
},
"resources": [
{
"apiVersion": "2016-09-01",
"name": "[variables('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('hostingPlanName')]",
"workerSizeId": "[parameters('appServicePlanWorkerSize')]",
"numberOfWorkers": "[parameters('appServicePlanNumWorkers')]"
},
"sku": {
"Tier": "[parameters('appServicePlanSku')]",
"Name": "[parameters('appServicePlanSkuCode')]"
},
"dependsOn": []
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"location": "[resourceGroup().location]",
"kind": "webapp",
"tags": {
"Environment": "production",
"displayName": "WebAppService"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
],
"properties": {
"name": "[variables('webAppName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms',variables('hostingPlanName'))]"
},
"resources": [
{
"name": "slotConfigNames",
"type": "config",
"apiVersion": "2015-08-01",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"
],
"tags": {
"displayName": "slotConfigNames"
},
"properties": {
"appSettingNames": []
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('stageSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
},
{
"apiVersion": "2015-08-01",
"name": "[variables('devSlotName')]",
"type": "slots",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('webAppName'))]"],
"properties": {},
"resources": []
}
]
}
]
}
问题
我正在尝试执行两个 ARM 模板(类似于上面的示例)以将两个不同的 Web 应用程序部署到同一个服务计划。
很明显,这两个 Web 应用程序必须调用相同的中央资源,以确保它们都部署到相同的应用程序服务资源名称并执行任何更改。
- 如果应用服务计划存在 = 部署网络应用。
- 如果应用服务计划不存在 = 创建服务计划然后部署网络应用程序。
- 如果应用服务计划已更改 = 部署服务计划更改(例如层更改),然后部署 Web 应用程序。
考虑到上面的环境描述,我有什么选择才能让它工作?
- 可能是发布定义中的 VSTS 全局参数?
- ARM 模板调用创建应用服务计划的 PowerShell 脚本?
热衷于遵循最佳实践。
我希望上面的描述足够详细。抱歉,如果遗漏了什么。谢谢。
ARM模板默认支持您的需求。基本上,如果 ARM 模板遇到存在的资源,如果属性不匹配,它将更新资源。否则它将使用您在 ARM 模板中设置的属性创建资源。
解决方案
我的解决方案是创建三个模板:
- 用于创建应用服务计划的模板 1。此 ARM 模板存储在 BLOB 容器中,发布管道可通过 SAS URI 访问。
- 用于创建网络应用程序 A 的模板 2。此模板使用 LINKED TEMPLATE 功能来调用和执行共享模板。
- 用于创建网络应用程序 B 的模板 3。此模板使用 LINKED TEMPLATE 功能来调用和执行共享模板。
结果
- 然后两个网络应用程序都发布到同一个服务器场,共享 实例。
- 部署的幂等性得以保持。
- 任何应用服务计划部署和任何修正的单一事实。
- 所需服务器场数量节省的资金。
示例
共享服务计划 - 共享服务计划的 ARM 模板示例:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"planLabel": {
"defaultValue": "shared-service-plan",
"type": "string"
}
},
"variables": {
"servicePlanName": "[concat(parameters('planLabel'),'-Plan-', uniqueString(resourceGroup().id))]"
},
"resources": [
{
"comments": "Creates an App Service Plan on the Standard (S1) SKU.",
"type": "Microsoft.Web/serverfarms",
"sku": {
"name": "S1",
"tier": "Standard",
"size": "S1",
"family": "S",
"capacity": 2
},
"kind": "app",
"name": "[variables('servicePlanName')]",
"apiVersion": "2016-09-01",
"location": "[resourceGroup().location]",
"properties": {
"name": "[variables('servicePlanName')]"
},
"dependsOn": []
}
],
"outputs": {
"servicePlanResourceId": {
"type": "string",
"value": "[resourceId('Microsoft.Web/serverfarms', variables('servicePlanName'))]"
},
"servicePlanName":{
"type": "string",
"value": "[variables('servicePlanName')]"
},
"resourceGroupName":{
"type": "string",
"value": "[resourceGroup().name]"
}
}
}
Web 应用程序 A - 包含链接模板的 ARM 模板示例:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"servicePlanLabel": {
"type": "string",
"metadata": {
"description": "The base name for the App Service Plan to be used in the linked template."
},
"defaultValue": "plan"
},
"appServicePlanResourceGroup": {
"type": "string",
"metadata": {
"Description": "The name of the Resource Group the shared App Service Plan will be deployed to."
},
"defaultValue": "group"
},
"appServicePlanTemplateUri": {
"type": "string",
"metadata": {
"description": "The URI to the App Service Plan linked template in BLOB"
}
}
},
"variables": {},
"resources": [
{
"apiVersion": "2017-05-10",
"name": "appServicePlanTemplate",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('appServicePlanResourceGroup')]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[parameters('appServicePlanTemplateUri')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"planLabel": {
"value": "[parameters('servicePlanLabel')]"
}
}
}
},
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('webAppName')]",
"location": "[resourceGroup().location]",
"kind": "webapp",
"tags": {
"Environment": "production",
"displayName": "App"
},
"dependsOn": [
"[resourceId(parameters('appServicePlanResourceGroup'), 'Microsoft.Resources/deployments', 'appServicePlanTemplate')]"
],
"properties": {}
}
}
}
希望这对某人有用。
谢谢 斯科特