Имеется шаблон, создание которого описано в посте Azure: ARM – ручное создание шаблона.
В шаблоне создаётся WebApp со swap-слотом, Storage Account, SQL сервер и две и базы.
Требуется добавить ещё две базы для свап-слота, и установить Slot setting чекбокс для Connection Strings, что бы приложение на PROD использовало свои базы, а STAGE – свои.
Шаблон, получившийся в результате – можно взять тут>>>.
Имеющиеся переменные:
... "variables": { "hostingPlanName": "[concat(resourceGroup().name, '-app-plan')]", "webSiteName": "[concat(resourceGroup().name, '-app')]", "sqlserverName": "[concat(resourceGroup().name, '-sql-server')]", "sqlDBbasename": "[concat(resourceGroup().name, '-DB-database')]", "sqlCMSbasename": "[concat(resourceGroup().name, '-CMS-database')]", "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'storage')]", "slotName": "staging" }, ...
Добавляем ещё две для двух баз:
... "sqlDBbasenameStage": "[concat(resourceGroup().name, '-DB-database', '-stage')]", "sqlCMSbasenameStage": "[concat(resourceGroup().name, '-CMS-database', '-stage')]", ...
Находим создание ресурса Microsoft.Sql/servers
, и в его resources
добавляем создание баз:
... { "name": "[variables('sqlDBbasenameStage')]", "type": "databases", "location": "[resourceGroup().location]", "tags": { "Application": "JM Platform swap-slot DB database" }, "apiVersion": "2014-04-01-preview", "dependsOn": [ "[variables('sqlserverName')]" ], "properties": { "edition": "[parameters('edition')]", "collation": "[parameters('collation')]", "maxSizeBytes": "[parameters('maxSizeBytes')]", "requestedServiceObjectiveName": "[parameters('requestedServiceObjectiveName')]" } }, { "name": "[variables('sqlCMSbasenameStage')]", "type": "databases", "location": "[resourceGroup().location]", "tags": { "Application": "JM Platform swap-slot CMS database" }, "apiVersion": "2014-04-01-preview", "dependsOn": [ "[variables('sqlserverName')]" ], "properties": { "edition": "[parameters('edition')]", "collation": "[parameters('collation')]", "maxSizeBytes": "[parameters('maxSizeBytes')]", "requestedServiceObjectiveName": "[parameters('requestedServiceObjectiveName')]" } }, ...
Переходим к Connection strings для WebApp.
Находим ресурс Microsoft.Web/sites
, в resources
которого имеется элемент "type": "config"
, в properties
которого указаны Connection strings:
... "properties": { "sqlDBConnection": { "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlDBbasename'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]", "type": "SQLServer" }, "sqlCMSConnection": { "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlCMSbasename'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]", "type": "SQLServer" } } ...
Для того, что бы эти параметры приложения были отмечены как Slot setting – добавляем ещё один ресурс "type": "config"
внутри блока resources ресурса "Microsoft.Web/sites"
, в котором перечисляем строки для Slot setting:
... { "apiVersion": "2014-11-01", "name": "slotconfignames", "type": "config", "dependsOn": [ "[variables('webSiteName')]" ], "properties": { "connectionStringNames": [ "sqlCMSConnection", "sqlDBConnection" ] } }, ...
Запускаем создание стека (“группы ресурсов”, но “стек”, по аналогии с AWS CloudFormation – мне нравится больше), и проверяем:
$ azure group create -l westeurope -n jm-platfrom-dev-eu-slot-test-7 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json ... data: Location: westeurope data: Provisioning State: Succeeded data: Tags: null data: info: group create command OK
Намного интереснее получилось со свап-слотом.
По аналогии с WebApp – для слота "type": "slots"
я добавил ресурс "type": "config"
со своим блоком properties
:
... { "apiVersion": "2014-11-01", "name": "slotconfignames", "type": "config", "dependsOn": [ "[variables('webSiteName')]" ], "properties": { "connectionStringNames": [ "sqlCMSConnectionStage", "sqlDBConnectionStage" ] } } ...
Что привело меня к удивительной ошибке:
$ azure group create -l westeurope -n amids-test-2 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json info: Executing command group create + Getting resource group amids-test-1 + Creating resource group amids-test-1 info: Created resource group amids-test-1 + Initializing template configurations and parameters + Creating a deployment error: Long running operation failed with error: 'At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.'. info: Error information has been recorded to /home/setevoy/.azure/azure.err error: group create command failed
И сама ошибка:
$ cat /home/setevoy/.azure/azure.err | grep body { body: '{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.","details":[{"code":"NotFound","message":"{\\r\\n \\"error\\": {\\r\\n \\"code\\": \\"BadRequest\\",\\r\\n \\"message\\": \\"\\"\\r\\n }\\r\\n}"}]}}'
Сообщение:
“details”:[{“code”:”NotFound”,”message”:”{\\r\\n \\”error\\”: {\\r\\n \\”code\\”: \\”BadRequest\\”,\\r\\n \\”message\\”: \\”\\”\\r\\n }\\r\\n}”}]}}’
Повергло меня в полное уныние, и я даже добавил его в пост Azure: почему никогда.
Помогла мне (на удивление) тех. поддержка Azure.
Для добавления Slot setting в Deployment slot приложения – в блок "name": "slotconfignames"
ресурса "type": "Microsoft.Web/sites"
добавляем ещё две базы:
... { "apiVersion": "2014-11-01", "name": "slotconfignames", "type": "config", "dependsOn": [ "[variables('webSiteName')]" ], "properties": { "connectionStringNames": [ "sqlCMSConnection", "sqlDBConnection","sqlCMSConnectionStage", "sqlDBConnectionStage" ] } }, ...
А в блок properties
слота – два параметра со строками подключения, используя переменные sqlCMSbasenameStage
и sqlDBbasenameStage
, добавленные ранее:
... "properties": { "sqlDBConnectionStage": { "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlDBbasenameStage'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]", "type": "SQLAzure" }, "sqlCMSConnectionStage": { "value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlCMSbasenameStage'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]", "type": "SQLAzure" } } ...
Структуру вложенности блоков проще понять со скрина PyCharm:
Запускаем (для дебага – отлично помогает -vv
):
$ azure group create -l westeurope -n jm-platfrom-dev-eu-slot-test-41 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json
Готово.