Azure: ARM – подключение вложенного шаблона

Автор: | 17/03/2017
 

Документация тут>>>.

Имеется шаблон для деплоя группы ресурсов – 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]

Готово.