Używanie połączonych i zagnieżdżonych szablonów podczas wdrażania zasobów platformy Azure

Aby wdrożyć złożone rozwiązania, możesz podzielić szablon usługi Azure Resource Manager (szablon arm) na wiele powiązanych szablonów, a następnie wdrożyć je razem za pomocą głównego szablonu. Powiązane szablony mogą być oddzielnymi plikami lub składnią szablonu osadzoną w głównym szablonie. W tym artykule użyto terminu połączony szablon do odwoływania się do oddzielnego pliku szablonu, do którego odwołuje się link z głównego szablonu. Używa on terminu szablonu zagnieżdżonego do odwoływania się do składni osadzonego szablonu w głównym szablonie.

W przypadku małych i średnich rozwiązań łatwiej jest zrozumieć i utrzymywać jeden szablon. Wszystkie zasoby i wartości są widoczne w jednym pliku. W przypadku zaawansowanych scenariuszy połączone szablony umożliwiają podzielenie rozwiązania na składniki przeznaczone do realizacji. Te szablony mogą być bez problemu używane wielokrotnie w innych scenariuszach.

Aby zapoznać się z samouczkiem, zobacz Samouczek: wdrażanie połączonego szablonu.

Uwaga

W przypadku szablonów połączonych lub zagnieżdżonych można ustawić tryb wdrażania tylko na przyrostowy. Szablon główny można jednak wdrożyć w trybie pełnym. Jeśli wdrożysz szablon główny w trybie pełnym, a połączony lub zagnieżdżony szablon jest przeznaczony dla tej samej grupy zasobów, zasoby wdrożone w połączonym lub zagnieżdżonym szablonie zostaną uwzględnione w ocenie wdrożenia w trybie pełnym. Połączona kolekcja zasobów wdrożonych w głównym szablonie i połączonych lub zagnieżdżonych szablonów jest porównywana z istniejącymi zasobami w grupie zasobów. Wszystkie zasoby nieuwzględniane w tej połączonej kolekcji zostaną usunięte.

Jeśli połączony lub zagnieżdżony szablon jest przeznaczony dla innej grupy zasobów, wdrożenie korzysta z trybu przyrostowego. Aby uzyskać więcej informacji, zobacz Zakres wdrożenia.

Napiwek

Zalecamy Bicep , ponieważ oferuje te same możliwości co szablony usługi ARM, a składnia jest łatwiejsza w użyciu. Aby dowiedzieć się więcej, zobacz moduły.

Szablon zagnieżdżony

Aby zagnieżdżać szablon, dodaj zasób wdrożenia do głównego szablonu. template We właściwości określ składnię szablonu.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          <nested-template-syntax>
        }
      }
    }
  ]
}

W poniższym przykładzie konto magazynu jest wdrażane za pomocą szablonu zagnieżdżonego.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "defaultValue": "[format('{0}{1}', 'store', uniqueString(resourceGroup().id))]"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Storage/storageAccounts",
              "apiVersion": "2022-09-01",
              "name": "[parameters('storageAccountName')]",
              "location": "[parameters('location')]",
              "sku": {
                "name": "Standard_LRS"
              },
              "kind": "StorageV2"
            }
          ]
        }
      }
    }
  ]
}

Zagnieżdżone zasoby nie mogą być używane w szablonie nazwy symbolicznej. W poniższym szablonie zagnieżdżony zasób konta magazynu nie może używać nazwy symbolicznej:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "languageVersion": "2.0",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "defaultValue": "[format('{0}{1}', 'storage', uniqueString(resourceGroup().id))]"

    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "resources": {
    "mainStorage": {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-09-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2"
    },
    "nestedResource": {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "nestedTemplate1",
      "properties": {
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Storage/storageAccounts",
              "apiVersion": "2022-09-01",
              "name": "[format('{0}nested', parameters('storageAccountName'))]",
              "location": "[parameters('location')]",
              "sku": {
                "name": "Standard_LRS"
              },
              "kind": "StorageV2"
            }
          ]
        }
      }
    }
  }
}

Zakres oceny wyrażeń w szablonach zagnieżdżonych

Podczas korzystania z szablonu zagnieżdżonego można określić, czy wyrażenia szablonów mają być oceniane w zakresie szablonu nadrzędnego, czy szablonu zagnieżdżonego. Zakres określa, jak są rozwiązywane parametry, zmienne i funkcje, takie jak resourceGroup i subskrypcja .

Zakres można ustawić za pomocą expressionEvaluationOptions właściwości . Domyślnie właściwość jest ustawiona expressionEvaluationOptions na outer, co oznacza, że używa zakresu szablonu nadrzędnego. Ustaw wartość , aby inner spowodować obliczanie wyrażeń w zakresie szablonu zagnieżdżonego.

Ważne

W przypadku languageVersion 2.0parametru wartość domyślna expressionEvaluationOptions właściwości to inner. Wartość outer jest zablokowana.

{
  "type": "Microsoft.Resources/deployments",
  "apiVersion": "2022-09-01",
  "name": "nestedTemplate1",
  "properties": {
    "expressionEvaluationOptions": {
      "scope": "inner"
    },
  ...

Uwaga

Gdy zakres jest ustawiony na outerwartość , nie można użyć reference funkcji w sekcji danych wyjściowych szablonu zagnieżdżonego dla zasobu wdrożonego w szablonie zagnieżdżonym. Aby zwrócić wartości wdrożonego zasobu w szablonie zagnieżdżonym, użyj inner zakresu lub przekonwertuj szablon zagnieżdżony na połączony szablon.

Poniższy szablon demonstruje sposób rozpoznawania wyrażeń szablonu zgodnie z zakresem. Zawiera zmienną o nazwie exampleVar zdefiniowaną zarówno w szablonie nadrzędnym, jak i szablonie zagnieżdżonym. Zwraca wartość zmiennej.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "variables": {
    "exampleVar": "from parent template"
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "nestedTemplate1",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "variables": {
            "exampleVar": "from nested template"
          },
          "resources": [
          ],
          "outputs": {
            "testVar": {
              "type": "string",
              "value": "[variables('exampleVar')]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
    "messageFromLinkedTemplate": {
      "type": "string",
      "value": "[reference('nestedTemplate1').outputs.testVar.value]"
    }
  }
}

Wartość exampleVar zmian w zależności od wartości scope właściwości w pliku expressionEvaluationOptions. W poniższej tabeli przedstawiono wyniki dla obu zakresów.

Zakres oceny Wyjście
Wewnętrzny z szablonu zagnieżdżonego
zewnętrzne (lub domyślne) z szablonu nadrzędnego

Poniższy przykład umożliwia wdrożenie serwera SQL i pobranie wpisu tajnego magazynu kluczy do użycia dla hasła. Zakres jest ustawiony na inner wartość , ponieważ dynamicznie tworzy identyfikator magazynu kluczy (zobacz adminPassword.reference.keyVault w szablonach parameterszewnętrznych) i przekazuje go jako parametr do zagnieżdżonego szablonu.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "The location where the resources will be deployed."
      }
    },
    "vaultName": {
      "type": "string",
      "metadata": {
        "description": "The name of the keyvault that contains the secret."
      }
    },
    "secretName": {
      "type": "string",
      "metadata": {
        "description": "The name of the secret."
      }
    },
    "vaultResourceGroupName": {
      "type": "string",
      "metadata": {
        "description": "The name of the resource group that contains the keyvault."
      }
    },
    "vaultSubscription": {
      "type": "string",
      "defaultValue": "[subscription().subscriptionId]",
      "metadata": {
        "description": "The name of the subscription that contains the keyvault."
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "adminLogin": {
            "value": "ghuser"
          },
          "adminPassword": {
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminLogin": {
              "type": "string"
            },
            "adminPassword": {
              "type": "securestring"
            },
            "location": {
              "type": "string"
            }
          },
          "variables": {
            "sqlServerName": "[format('sql-{0}sql', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2022-05-01-preview",
              "name": "[variables('sqlServerName')]",
              "location": "[parameters('location')]",
              "properties": {
                "administratorLogin": "[parameters('adminLogin')]",
                "administratorLoginPassword": "[parameters('adminPassword')]"
              }
            }
          ],
          "outputs": {
            "sqlFQDN": {
              "type": "string",
              "value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
  }
}

Należy zachować ostrożność podczas używania bezpiecznych wartości parametrów w zagnieżdżonym szablonie. Jeśli ustawisz zakres na zewnętrzny, bezpieczne wartości są przechowywane jako zwykły tekst w historii wdrażania. Użytkownik wyświetlający szablon w historii wdrażania może zobaczyć bezpieczne wartości. Zamiast tego należy użyć zakresu wewnętrznego lub dodać do szablonu nadrzędnego zasoby, które wymagają bezpiecznych wartości.

Poniższy fragment pokazuje, które wartości są bezpieczne i które nie są bezpieczne.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine."
      }
    },
    "adminPasswordOrKey": {
      "type": "securestring",
      "metadata": {
        "description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
      }
    }
  },
  ...
  "resources": [
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2023-03-01",
      "name": "mainTemplate",
      "properties": {
        ...
        "osProfile": {
          "computerName": "mainTemplate",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPasswordOrKey')]" // Yes, secure because resource is in parent template
        }
      }
    },
    {
      "name": "outer",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "outer"
        },
        "mode": "Incremental",
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "resources": [
            {
              "type": "Microsoft.Compute/virtualMachines",
              "apiVersion": "2023-03-01",
              "name": "outer",
              "properties": {
                ...
                "osProfile": {
                  "computerName": "outer",
                  "adminUsername": "[parameters('adminUsername')]",
                  "adminPassword": "[parameters('adminPasswordOrKey')]" // No, not secure because resource is in nested template with outer scope
                }
              }
            }
          ]
        }
      }
    },
    {
      "name": "inner",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "properties": {
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "mode": "Incremental",
        "parameters": {
          "adminPasswordOrKey": {
              "value": "[parameters('adminPasswordOrKey')]"
          },
          "adminUsername": {
              "value": "[parameters('adminUsername')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminUsername": {
              "type": "string",
              "metadata": {
                "description": "Username for the Virtual Machine."
              }
            },
            "adminPasswordOrKey": {
              "type": "securestring",
              "metadata": {
                "description": "SSH Key or password for the Virtual Machine. SSH key is recommended."
              }
            }
          },
          "resources": [
            {
              "type": "Microsoft.Compute/virtualMachines",
              "apiVersion": "2023-03-01",
              "name": "inner",
              "properties": {
                ...
                "osProfile": {
                  "computerName": "inner",
                  "adminUsername": "[parameters('adminUsername')]",
                  "adminPassword": "[parameters('adminPasswordOrKey')]" // Yes, secure because resource is in nested template and scope is inner
                }
              }
            }
          ]
        }
      }
    }
  ]
}

Szablon połączony

Aby połączyć szablon, dodaj zasób wdrożenia do głównego szablonu. templateLink We właściwości określ identyfikator URI szablonu do uwzględnienia. Poniższy przykład zawiera linki do szablonu, który znajduje się na koncie magazynu.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
          "contentVersion":"1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
  }
}

W przypadku odwoływania się do połączonego szablonu wartość uri nie może być plikiem lokalnym ani plikiem dostępnym tylko w sieci lokalnej. Usługa Azure Resource Manager musi mieć dostęp do szablonu. Podaj wartość identyfikatora URI, która można pobrać jako HTTP lub HTTPS.

Możesz odwoływać się do szablonów przy użyciu parametrów zawierających protokół HTTP lub HTTPS. Na przykład typowym wzorcem jest użycie parametru _artifactsLocation . Możesz ustawić połączony szablon z wyrażeniem, na przykład:

"uri": "[format('{0}/shared/os-disk-parts-md.json{1}', parameters('_artifactsLocation'), parameters('_artifactsLocationSasToken'))]"

Jeśli łączysz się z szablonem w usłudze GitHub, użyj nieprzetworzonego adresu URL. Link ma format: https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json. Aby uzyskać link nieprzetworzone, wybierz pozycję Nieprzetworzone.

Screenshot of selecting raw URL in GitHub.

Uwaga

Aby wdrożyć szablon lub odwołać się do połączonego szablonu przechowywanego w prywatnym repozytorium GitHub, zobacz rozwiązanie niestandardowe opisane w artykule Tworzenie niestandardowej i bezpiecznej oferty witryny Azure Portal. Możesz utworzyć funkcję platformy Azure, która ściąga token Usługi GitHub z usługi Azure Key Vault.

W przypadku szablonów połączonych można zagnieżdżać wdrożenie innej niż symboliczna nazwa wewnątrz szablonu o nazwie symbolicznej lub zagnieżdżać wdrożenie nazwy symbolicznej wewnątrz szablonu innego niż symboliczne albo zagnieżdżać wdrożenie nazwy symbolicznej wewnątrz innego szablonu nazwy symbolicznej lub odwrotnie.

Parametry połączonego szablonu

Parametry połączonego szablonu można podać w pliku zewnętrznym lub wbudowanym. W przypadku podawania pliku parametrów zewnętrznych użyj parametersLink właściwości :

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "name": "linkedTemplate",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
        "contentVersion": "1.0.0.0"
      },
      "parametersLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.parameters.json",
        "contentVersion": "1.0.0.0"
      }
    }
  }
]

Aby przekazać wbudowane wartości parametrów parameters , użyj właściwości .

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "name": "linkedTemplate",
    "properties": {
      "mode": "Incremental",
      "templateLink": {
        "uri": "https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json",
        "contentVersion": "1.0.0.0"
      },
      "parameters": {
        "storageAccountName": {
          "value": "[parameters('storageAccountName')]"
        }
      }
    }
  }
]

Nie można używać zarówno parametrów wbudowanych, jak i linku do pliku parametrów. Wdrożenie kończy się niepowodzeniem z powodu błędu po określeniu obu parametersLink tych elementów.parameters

Używanie ścieżki względnej dla połączonych szablonów

Właściwość relativePath ułatwia tworzenie połączonych Microsoft.Resources/deployments szablonów. Tej właściwości można użyć do wdrożenia zdalnego połączonego szablonu w lokalizacji względem elementu nadrzędnego. Ta funkcja wymaga przygotowania i udostępnienia wszystkich plików szablonów przy użyciu zdalnego identyfikatora URI, takiego jak GitHub lub konto usługi Azure Storage. Gdy główny szablon jest wywoływany przy użyciu identyfikatora URI z programu Azure PowerShell lub interfejsu wiersza polecenia platformy Azure, identyfikator URI wdrożenia podrzędnego jest kombinacją elementu nadrzędnego i względnegoPath.

Uwaga

Podczas tworzenia szablonuSpec wszystkie szablony, do których odwołuje się relativePath właściwość, są pakowane w zasobie templateSpec za pomocą programu Azure PowerShell lub interfejsu wiersza polecenia platformy Azure. Nie wymaga on przygotowania plików. Aby uzyskać więcej informacji, zobacz Tworzenie specyfikacji szablonu z połączonymi szablonami.

Załóżmy, że struktura folderów wygląda następująco:

Diagram showing folder structure for Resource Manager linked template relative path.

Poniższy szablon pokazuje, jak mainTemplate.json wdraża nestedChild.json pokazane na poprzedniej ilustracji.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "functions": [],
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "childLinked",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "relativePath": "children/nestedChild.json"
        }
      }
    }
  ],
  "outputs": {}
}

W poniższym wdrożeniu identyfikator URI połączonego szablonu w poprzednim szablonie to https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/linked-template-relpath/children/nestedChild.json.

New-AzResourceGroupDeployment `
  -Name linkedTemplateWithRelativePath `
  -ResourceGroupName "myResourceGroup" `
  -TemplateUri "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/linked-template-relpath/mainTemplate.json"

Aby wdrożyć połączone szablony ze ścieżką względną przechowywaną na koncie usługi Azure Storage, użyj parametru QueryString/query-string , aby określić token SAS, który ma być używany z parametrem TemplateUri. Ten parametr jest obsługiwany tylko przez interfejs wiersza polecenia platformy Azure w wersji 2.18 lub nowszej oraz program Azure PowerShell w wersji 5.4 lub nowszej.

New-AzResourceGroupDeployment `
  -Name linkedTemplateWithRelativePath `
  -ResourceGroupName "myResourceGroup" `
  -TemplateUri "https://stage20210126.blob.core.windows.net/template-staging/mainTemplate.json" `
  -QueryString $sasToken

Upewnij się, że w funkcji QueryString nie ma wiodącego ciągu "?". Wdrożenie dodaje jeden podczas tworzenia identyfikatora URI dla wdrożeń.

Specyfikacje szablonu

Zamiast utrzymywać połączone szablony w dostępnym punkcie końcowym, możesz utworzyć specyfikację szablonu, która pakuje główny szablon i jego połączone szablony w jedną jednostkę, którą można wdrożyć. Specyfikacja szablonu to zasób w ramach subskrypcji platformy Azure. Ułatwia bezpieczne udostępnianie szablonu użytkownikom w organizacji. Aby udzielić dostępu do specyfikacji szablonu, należy użyć kontroli dostępu opartej na rolach (RBAC) platformy Azure.

Aby uzyskać więcej informacji, zobacz:

Zależności

Podobnie jak w przypadku innych typów zasobów, można ustawić zależności między zagnieżdżonym/połączonymi szablonami. Jeśli zasoby w jednym zagnieżdżonym/połączonym szablonie muszą zostać wdrożone przed użyciem zasobów w drugim zagnieżdżonym/połączonym szablonie, ustaw drugi szablon zależny od pierwszego.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate1",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'firstresources.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate2",
      "dependsOn": [
        "[resourceId('Microsoft.Resources/deployments', 'linkedTemplate1')]"
      ],
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'secondresources.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ]
}

contentVersion

Nie musisz podawać contentVersion właściwości właściwości templateLink lub parametersLink . Jeśli nie podasz contentVersionelementu , zostanie wdrożona bieżąca wersja szablonu. Jeśli podasz wartość wersji zawartości, musi być zgodna z wersją w połączonym szablonie; w przeciwnym razie wdrożenie kończy się niepowodzeniem z powodu błędu.

W poprzednich przykładach pokazano trwale zakodowane wartości adresów URL dla linków szablonu. Takie podejście może działać w przypadku prostego szablonu, ale nie działa dobrze w przypadku dużego zestawu szablonów modułowych. Zamiast tego możesz utworzyć zmienną statyczną, która przechowuje podstawowy adres URL głównego szablonu, a następnie dynamicznie tworzyć adresy URL dla połączonych szablonów z tego podstawowego adresu URL. Zaletą tego podejścia jest możliwość łatwego przenoszenia lub rozwidlenia szablonu, ponieważ trzeba zmienić tylko zmienną statyczną w głównym szablonie. Główny szablon przekazuje poprawne identyfikatory URI w całym zdekompilowany szablon.

W poniższym przykładzie pokazano, jak za pomocą podstawowego adresu URL utworzyć dwa adresy URL dla połączonych szablonów (sharedTemplateUrl i vmTemplateUrl).

"variables": {
  "templateBaseUrl": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/application-workloads/postgre/postgresql-on-ubuntu/",
  "sharedTemplateUrl": "[uri(variables('templateBaseUrl'), 'shared-resources.json')]",
  "vmTemplateUrl": "[uri(variables('templateBaseUrl'), 'database-2disk-resources.json')]"
}

Możesz również użyć metody deployment(), aby uzyskać podstawowy adres URL bieżącego szablonu i użyć go do pobrania adresu URL dla innych szablonów w tej samej lokalizacji. Takie podejście jest przydatne, jeśli lokalizacja szablonu ulegnie zmianie lub chcesz uniknąć twardych adresów URL kodowania w pliku szablonu. Właściwość templateLink jest zwracana tylko podczas łączenia z szablonem zdalnym przy użyciu adresu URL. Jeśli używasz szablonu lokalnego, ta właściwość nie jest dostępna.

"variables": {
  "sharedTemplateUrl": "[uri(deployment().properties.templateLink.uri, 'shared-resources.json')]"
}

Ostatecznie należy użyć zmiennej we uri właściwości templateLink właściwości .

"templateLink": {
 "uri": "[variables('sharedTemplateUrl')]",
 "contentVersion":"1.0.0.0"
}

Korzystanie z kopiowania

Aby utworzyć wiele wystąpień zasobu przy użyciu szablonu zagnieżdżonego, dodaj copy element na poziomie Microsoft.Resources/deployments zasobu. Jeśli zakres to inner, możesz dodać kopię w szablonie zagnieżdżonym.

Poniższy przykładowy szablon pokazuje, jak używać z copy zagnieżdżonym szablonem.

"resources": [
  {
    "type": "Microsoft.Resources/deployments",
    "apiVersion": "2022-09-01",
    "name": "[format('nestedTemplate{0}', copyIndex())]",
    // yes, copy works here
    "copy": {
      "name": "storagecopy",
      "count": 2
    },
    "properties": {
      "mode": "Incremental",
      "expressionEvaluationOptions": {
        "scope": "inner"
      },
      "template": {
        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "resources": [
          {
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2022-09-01",
            "name": "[format('{0}{1}', variables('storageName'), copyIndex())]",
            "location": "West US",
            "sku": {
              "name": "Standard_LRS"
            },
            "kind": "StorageV2"
            // Copy works here when scope is inner
            // But, when scope is default or outer, you get an error
            // "copy": {
            //   "name": "storagecopy",
            //   "count": 2
            // }
          }
        ]
      }
    }
  }
]

Pobieranie wartości z połączonego szablonu

Aby uzyskać wartość wyjściową z połączonego szablonu, pobierz wartość właściwości ze składnią, na przykład: "[reference('deploymentName').outputs.propertyName.value]".

Podczas pobierania właściwości wyjściowej z połączonego szablonu nazwa właściwości nie może zawierać kreski.

W poniższych przykładach pokazano, jak odwoływać się do połączonego szablonu i pobierać wartość wyjściową. Połączony szablon zwraca prosty komunikat. Najpierw połączony szablon:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [],
  "outputs": {
    "greetingMessage": {
      "value": "Hello World",
      "type": "string"
    }
  }
}

Główny szablon wdraża połączony szablon i pobiera zwróconą wartość. Zwróć uwagę, że odwołuje się on do zasobu wdrożenia według nazwy i używa nazwy właściwości zwróconej przez połączony szablon.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {},
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'helloworld.json')]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
    "messageFromLinkedTemplate": {
      "type": "string",
      "value": "[reference('linkedTemplate').outputs.greetingMessage.value]"
    }
  }
}

Poniższy przykład przedstawia szablon, który wdraża publiczny adres IP i zwraca identyfikator zasobu platformy Azure dla tego publicznego adresu IP:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "publicIPAddresses_name": {
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2021-02-01",
      "name": "[parameters('publicIPAddresses_name')]",
      "location": "eastus",
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Dynamic",
        "idleTimeoutInMinutes": 4
      },
      "dependsOn": []
    }
  ],
  "outputs": {
    "resourceID": {
      "type": "string",
      "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_name'))]"
    }
  }
}

Aby użyć publicznego adresu IP z poprzedniego szablonu podczas wdrażania modułu równoważenia obciążenia, połącz się z szablonem i zadeklaruj zależność od Microsoft.Resources/deployments zasobu. Publiczny adres IP modułu równoważenia obciążenia jest ustawiony na wartość wyjściową z połączonego szablonu.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "loadBalancers_name": {
      "defaultValue": "mylb",
      "type": "string"
    },
    "publicIPAddresses_name": {
      "defaultValue": "myip",
      "type": "string"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/loadBalancers",
      "apiVersion": "2021-02-01",
      "name": "[parameters('loadBalancers_name')]",
      "location": "eastus",
      "properties": {
        "frontendIPConfigurations": [
          {
            "name": "LoadBalancerFrontEnd",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[reference('linkedTemplate').outputs.resourceID.value]"
              }
            }
          }
        ],
        "backendAddressPools": [],
        "loadBalancingRules": [],
        "probes": [],
        "inboundNatRules": [],
        "outboundNatRules": [],
        "inboundNatPools": []
      },
      "dependsOn": [
        "[resourceId('Microsoft.Resources/deployments', 'linkedTemplate')]"
      ]
    },
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2021-04-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[uri(deployment().properties.templateLink.uri, 'public-ip.json')]",
          "contentVersion": "1.0.0.0"
        },
        "parameters": {
          "publicIPAddresses_name": { "value": "[parameters('publicIPAddresses_name')]" }
        }
      }
    }
  ]
}

Historia wdrożenia

Usługa Resource Manager przetwarza każdy szablon jako oddzielne wdrożenie w historii wdrażania. Główny szablon z trzema połączonymi lub zagnieżdżonym szablonem jest wyświetlany w historii wdrażania jako:

Screenshot of deployment history in Azure portal.

Możesz użyć tych oddzielnych wpisów w historii, aby pobrać wartości wyjściowe po wdrożeniu. Poniższy szablon tworzy publiczny adres IP i zwraca adres IP:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "publicIPAddresses_name": {
      "type": "string"
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Network/publicIPAddresses",
      "apiVersion": "2023-04-01",
      "name": "[parameters('publicIPAddresses_name')]",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAddressVersion": "IPv4",
        "publicIPAllocationMethod": "Static",
        "idleTimeoutInMinutes": 4,
        "dnsSettings": {
          "domainNameLabel": "[format('{0}{1}', parameters('publicIPAddresses_name'), uniqueString(resourceGroup().id))]"
        }
      },
      "dependsOn": []
    }
  ],
  "outputs": {
    "returnedIPAddress": {
      "type": "string",
      "value": "[reference(parameters('publicIPAddresses_name')).ipAddress]"
    }
  }
}

Poniższy szablon zawiera linki do poprzedniego szablonu. Tworzy trzy publiczne adresy IP.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
  },
  "variables": {},
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "[format('linkedTemplate{0}', copyIndex())]",
      "copy": {
        "count": 3,
        "name": "ip-loop"
      },
      "properties": {
        "mode": "Incremental",
        "templateLink": {
        "uri": "[uri(deployment().properties.templateLink.uri, 'static-public-ip.json')]",
        "contentVersion": "1.0.0.0"
        },
        "parameters":{
          "publicIPAddresses_name":{"value": "[format('myip-{0}', copyIndex())]"}
        }
      }
    }
  ]
}

Po wdrożeniu można pobrać wartości wyjściowe za pomocą następującego skryptu programu PowerShell:

$loopCount = 3
for ($i = 0; $i -lt $loopCount; $i++)
{
  $name = 'linkedTemplate' + $i;
  $deployment = Get-AzResourceGroupDeployment -ResourceGroupName examplegroup -Name $name
  Write-Output "deployment $($deployment.DeploymentName) returned $($deployment.Outputs.returnedIPAddress.value)"
}

Lub skrypt interfejsu wiersza polecenia platformy Azure w powłoce powłoki Bash:

#!/bin/bash

for i in 0 1 2;
do
  name="linkedTemplate$i";
  deployment=$(az deployment group show -g examplegroup -n $name);
  ip=$(echo $deployment | jq .properties.outputs.returnedIPAddress.value);
  echo "deployment $name returned $ip";
done

Zabezpieczanie szablonu zewnętrznego

Mimo że połączony szablon musi być dostępny zewnętrznie, nie musi być ogólnie dostępny dla opinii publicznej. Szablon można dodać do prywatnego konta magazynu, które jest dostępne tylko dla właściciela konta magazynu. Następnie utworzysz token sygnatury dostępu współdzielonego (SAS), aby umożliwić dostęp podczas wdrażania. Dodasz ten token SAS do identyfikatora URI połączonego szablonu. Mimo że token jest przekazywany jako bezpieczny ciąg, identyfikator URI połączonego szablonu, w tym token SAS, jest rejestrowany w operacjach wdrażania. Aby ograniczyć narażenie, ustaw wygaśnięcie tokenu.

Plik parametrów może być również ograniczony do dostępu za pośrednictwem tokenu SAS.

Obecnie nie można połączyć się z szablonem na koncie magazynu, które znajduje się za zaporą usługi Azure Storage.

Ważne

Zamiast zabezpieczać połączony szablon przy użyciu tokenu SAS, rozważ utworzenie specyfikacji szablonu. Specyfikacja szablonu bezpiecznie przechowuje główny szablon i jego połączone szablony jako zasób w ramach subskrypcji platformy Azure. Kontrola dostępu oparta na rolach platformy Azure służy do udzielania dostępu użytkownikom, którzy muszą wdrożyć szablon.

W poniższym przykładzie pokazano, jak przekazać token SAS podczas łączenia z szablonem:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "containerSasToken": { "type": "securestring" }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "name": "linkedTemplate",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "uri": "[format('{0}{1}', uri(deployment().properties.templateLink.uri, 'helloworld.json'), parameters('containerSasToken'))]",
          "contentVersion": "1.0.0.0"
        }
      }
    }
  ],
  "outputs": {
  }
}

W programie PowerShell uzyskasz token dla kontenera i wdrożysz szablony przy użyciu następujących poleceń. Zwróć uwagę, że containerSasToken parametr jest zdefiniowany w szablonie. Nie jest to parametr w poleceniu New-AzResourceGroupDeployment .

Set-AzCurrentStorageAccount -ResourceGroupName ManageGroup -Name storagecontosotemplates
$token = New-AzStorageContainerSASToken -Name templates -Permission r -ExpiryTime (Get-Date).AddMinutes(30.0)
$url = (Get-AzStorageBlob -Container templates -Blob parent.json).ICloudBlob.uri.AbsoluteUri
New-AzResourceGroupDeployment -ResourceGroupName ExampleGroup -TemplateUri ($url + $token) -containerSasToken $token

W przypadku interfejsu wiersza polecenia platformy Azure w powłoce Bash uzyskasz token dla kontenera i wdrożysz szablony przy użyciu następującego kodu:

#!/bin/bash

expiretime=$(date -u -d '30 minutes' +%Y-%m-%dT%H:%MZ)
connection=$(az storage account show-connection-string \
  --resource-group ManageGroup \
  --name storagecontosotemplates \
  --query connectionString)
token=$(az storage container generate-sas \
  --name templates \
  --expiry $expiretime \
  --permissions r \
  --output tsv \
  --connection-string $connection)
url=$(az storage blob url \
  --container-name templates \
  --name parent.json \
  --output tsv \
  --connection-string $connection)
parameter='{"containerSasToken":{"value":"?'$token'"}}'
az deployment group create --resource-group ExampleGroup --template-uri $url?$token --parameters $parameter

Przykładowe szablony

W poniższych przykładach przedstawiono typowe zastosowania połączonych szablonów.

Szablon główny Szablon połączony opis
Witaj, świecie połączony szablon Zwraca ciąg z połączonego szablonu.
Moduł równoważenia obciążenia z publicznym adresem IP połączony szablon Zwraca publiczny adres IP z połączonego szablonu i ustawia wartość w module równoważenia obciążenia.
Wiele adresów IP połączony szablon Tworzy kilka publicznych adresów IP w połączonym szablonie.

Następne kroki