Документация тут>>>.
Имеется шаблон для деплоя группы ресурсов — 2 VMSS, балансировщики, подсети и группы безопасности. Одна — для VMSS Docker Swarm-менеджеров, вторая — для Swarm-нод.
Задача — вынести описание групп безопасности в отдельные шаблоны, что бы подключать их в зависимости от окружения — для Dev свои, для Prod — свои и т.д.
Ресурс Network Security Group для нод выглядит так:
...
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('NodesNSGname')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "NSG - Remote Access"
},
"properties": {
"securityRules": [
{
"name": "AllowSSHAll",
"properties": {
"description": "Allow SSH",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
},
...
Пробуем вложенность.
Создаём отдельный шаблон, например jm-website-nsg-dev.json, копируем в него ресурс NSG:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('NodesNSGname')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "NSG - Remote Access"
},
"properties": {
"securityRules": [
{
"name": "AllowSSHAll",
"properties": {
"description": "Allow SSH",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 100,
"direction": "Inbound"
}
}
]
}
}
]
}
Доступ к шаблонам — только по HTTP/S, поэтому — загружаем его в Storage Account:
[simterm]
$ export AZURE_STORAGE_ACCOUNT=utils $ export AZURE_STORAGE_ACCESS_KEY=tOkX***6Bw==
[/simterm]
Выполняем:
[simterm]
$ azure storage blob upload '/home/setevoy/Work/BER.JM/azure-infrastructure/jm-website/jm-website-nsg-dev.json' templates info: Executing command storage blob upload + Checking blob jm-website-nsg-dev.json in container templates + Uploading /home/setevoy/Work/BER.JM/azure-infrastructure/jm-website/jm-website-nsg-dev.json to blob jm-website-nsg-dev.json in container templates ...
[/simterm]
В главном шаблоне на место ресурса NSG вписываем ресурс деплоя:
...
{
"apiVersion": "2015-01-01",
"name": "linkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri": "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json",
"contentVersion": "1.0.0.0"
},
"parameters": {
"StorageAccountName":{"value": "[parameters('storageAccountName')]"}
}
}
},
...
Пробуем:
[simterm]
$ azure group create -l westeurope -n jm-website-sw-nsg-test-1 -f jm-website-sw.json -e jm-website-sw.parameters.json info: Executing command group create + Getting resource group jm-website-sw-nsg-test-1 + Creating resource group jm-website-sw-nsg-test-1 info: Created resource group jm-website-sw-nsg-test-1 + Initializing template configurations and parameters + Creating a deployment error: InvalidContentLink : Unable to download deployment content from 'https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json'. The tracking Id is '7c85bd15-1377-417a-b6f1-4e08a64eb87a'. Please see https://aka.ms/arm-deploy for usage details. ...
[/simterm]
Странно — ARM при валидации не упал. Значит — в целом схема уже рабочая.
Авторизация.
Переходим в Portal > Storage accounts, генерируем SAS-токен:
Выносим его в параметр:
...
"parameters": {
"SAStoken": {
"type": "string",
"defaultValue": "?sv=2016-05-31&ss=bfqt&srt=sco&sp=ra&se=2018-03-17T20:31:25Z&st=2017-03-17T12:31:25Z&spr=https&sig=QWy2Sp***%3D"
},
...
Обновляем URI в главном шаблоне:
...
"templateLink": {
"uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json', parameters('SAStoken'))]",
"contentVersion": "1.0.0.0"
},
...
Пробуем:
... error: InvalidContentLink : Unable to download deployment content from 'https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json?sv=2016-05-31&ss=bfqt&srt=sco&sp=ra&se=2018-03-17T20:31:25Z&st=2017-03-17T12:31:25Z&spr=https&sig=QWy2***U%3D'. The tracking Id is '6bad400b-6e1e-43cd-98c4-45b324500be5'. Please see https://aka.ms/arm-deploy for usage details. ...
Ну, ок. Ничего удивительного. Сделаем авторизацию позже, а пока — устанавливаем на контейнер права доступа Blob (пубичный доступ на чтение).
Пробуем снова:
[simterm]
$ azure group create -l westeurope -n jm-website-sw-nsg-test-1 -f jm-website-sw.json -e jm-website-sw.parameters.json info: Executing command group create + Getting resource group jm-website-sw-nsg-test-1 + Updating resource group jm-website-sw-nsg-test-1 info: Updated resource group jm-website-sw-nsg-test-1 + Initializing template configurations and parameters + Creating a deployment error: InvalidTemplate : Deployment template validation failed: 'The template parameters 'StorageAccountName' in the parameters file are not valid; they are not present in the original template and can therefore not be provided at deployment time. The only supported parameters for this template are 'adminPassword'. Please see https://aka.ms/arm-deploy/#parameter-file for usage details.'. ...
[/simterm]
Отлично! Уже ругается на параметры — StorageAccountName, т.к. ресурс деплоя просто скопирован из документации.
В нашем шаблоне NSG мы используем переменную NodesNSGname:
...
"name": "[variables('NodesNSGname')]",
...
В файле шаблона — создаём параметр NodesNSGname:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"NodesNSGname": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[parameters('NodesNSGname')]",
...
Обновляем ресурс деплоя в основном шаблоне, передаём во вложенный шаблон переменную NodesNSGname из главного шаблона:
... "nodesNSGname": "[concat(resourceGroup().name,'-nodes-nsg')]", ...
В ресурсе деплоя указываем:
...
"parameters": {
"NodesNSGname":{"value": "[variables('NodesNSGname')]"}
...
Полностью он сейчас выглядит так:
...
{
"apiVersion": "2015-01-01",
"name": "linkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri": "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json",
"contentVersion": "1.0.0.0"
},
"parameters": {
"NodesNSGname":{"value": "[variables('NodesNSGname')]"}
}
}
},
...
Обновляем шаблон в Storage account-е:
[simterm]
$ azure storage blob upload '/home/setevoy/Work/BER.JM/azure-infrastructure/jm-website/jm-website-nsg-dev.json' templates info: Executing command storage blob upload + Checking blob jm-website-nsg-dev.json in container templates Do you want to overwrite the blob jm-website-nsg-dev.json in container templates? y ...
[/simterm]
Пробуем:
[simterm]
$ azure sazure group create -l westeurope -n jm-website-sw-nsg-test-1 -f jm-website-sw.json -e jm-website-sw.parameters.json info: Executing command group create + Getting resource group jm-website-sw-nsg-test-1 + Updating resource group jm-website-sw-nsg-test-1 info: Updated resource group jm-website-sw-nsg-test-1 + Initializing template configurations and parameters + Creating a deployment info: Created template deployment "jm-website-sw" data: Id: /subscriptions/0a4f2b9c-***-40b17ef8c3ab/resourceGroups/jm-website-sw-nsg-test-1 data: Name: jm-website-sw-nsg-test-1 data: Location: westeurope data: Provisioning State: Succeeded data: Tags: null data: info: group create command OK
[/simterm]
Проверяем:
[simterm]
$ azure group deployment show -g jm-website-sw-nsg-test-1 info: Executing command group deployment show + Getting deployments data: DeploymentName : jm-website-sw data: ResourceGroupName : jm-website-sw-nsg-test-1 data: ProvisioningState : Running ...
[/simterm]
В Portal-е, деплой главного шаблона:
Деплой вложенного шаблона:
Фиксим авторизацию.
Возвращаем права на контейнер — Private.
Пробуем curl-ом:
[simterm]
$ curl https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json <?xml version="1.0" encoding="utf-8"?><Error><Code>ResourceNotFound</Code><Message>The specified resource does not exist. ...
[/simterm]
Пробуем с токеном:
$ curl "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json/?sv=2016-05-31&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-17T21:18:58Z&st=2017-03-17T13:18:58Z&spr=https,http&sig=QIN***%3D"
Ага, теперь видна ошибка:
Time:2017-03-17T11:23:58.3677617Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Fri, 17 Mar 2017 13:18:58 GMT] - Expiry [Tue, 17 Mar 2020 21:18:58 GMT] - Current [Fri, 17 Mar 2017 11:23:58 GMT]</AuthenticationErrorDetail></Error>
При деплое через ARM её не видел.
Вчитываемся в неё:
Time:2017-03-17T11:36:37.3456373Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Fri, 17 Mar 2017 13:33:28 GMT] — Expiry [Fri, 17 Mar 2017 21:33:28 GMT] — Current [Fri, 17 Mar 2017 11:36:37 GMT]</AuthenticationErrorDetail></Error>
Start 13:33:28
Expiry 21:33:28
Current 11:36:37
Current 11:36:37
Временная зона.
Генерируем токен заново, указываем зону UTC +2 (Киев):
Проверяем:
[simterm]
$ curl "https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json/?sv=2016-05-31&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-17T19:37:37Z&st=2017-03-17T11:37:37Z&spr=https&sig=IlrsuM***0hk%3D"
[/simterm]
Теперь ошибка 404.
А через ARM — работает.
В основном шаблоне обновляем параметр SAStoken:
"parameters": {
"SAStoken": {
"type": "string",
"defaultValue": "?sv=2016-05-31&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-17T19:37:37Z&st=2017-03-17T11:37:37Z&spr=https&sig=Ilr***k%3D"
},
...
И uri:
...
{
"apiVersion": "2015-01-01",
"name": "linkedTemplate",
"type": "Microsoft.Resources/deployments",
"properties": {
"mode": "incremental",
"templateLink": {
"uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-dev.json', parameters('SAStoken'))]",
"contentVersion": "1.0.0.0"
...
Выполняем, проверяем:
[simterm]
$ azure group create -l westeurope -n jm-website-sw-nsg-test-2 -f jm-website-sw.json -e jm-website-sw.parameters.json info: Executing command group create + Getting resource group jm-website-sw-nsg-test-2 + Creating resource group jm-website-sw-nsg-test-2 info: Created resource group jm-website-sw-nsg-test-2 + Initializing template configurations and parameters + Creating a deployment info: Created template deployment "jm-website-sw" ...
[/simterm]
С этим разобрались.
Последнее, что хотелось бы слделать — это выбор шаблона в зависимости от того, на какое окружение выполняется развёртывание группы ресурсов.
Проще всего — через добавление нового параметра:
...
"environment": {
"type": "string",
"metadata": {
"description": "dev, qa, staging, prod"
},
"defaultValue": "dev",
"allowedValues": [
"dev",
"qa",
"staging",
"production"
]
},
...
И обновляем uri:
...
"uri": "[concat('https://utils.blob.core.windows.net/templates/jm-website-nsg-', parameters('environment'), '.json', parameters('SAStoken'))]",
...
Проверяем:
[simterm]
$ azure group create -l westeurope -n jm-website-sw-nsg-test-3 -f jm-website-sw.json -e jm-website-sw.parameters.json
[/simterm]
Готово.




