Menggunakan templat yang ditautkan dan bercabang saat menerapkan sumber daya Azure

Untuk menyebarkan solusi kompleks, Anda dapat memecah templat Azure Resource Manager (templat ARM) menjadi banyak templat terkait, lalu menyebarkannya bersama-sama melalui templat utama. Templat terkait dapat berupa file terpisah atau sintaks templat yang disematkan dalam templat utama. Artikel ini menggunakan istilah templat tertaut untuk merujuk ke file templat terpisah yang direferensikan melalui tautan dari templat utama. Istilah templat berlapis yang digunakan di sini merujuk ke sintaks templat yang disematkan dalam templat utama.

Untuk solusi kecil hingga menengah, satu templat lebih mudah dipahami dan dikelola. Anda dapat melihat semua sumber daya dan nilai dalam satu file. Untuk skenario tingkat lanjut, templat yang ditautkan memungkinkan Anda untuk menguraikan solusi menjadi komponen yang ditargetkan. Anda dapat dengan mudah menggunakan kembali templat ini untuk skenario lain.

Untuk tutorial, lihat Tutorial: menyebarkan templat tertaut.

Catatan

Untuk templat tertaut atau berlapis, Anda hanya dapat mengatur mode penyebaran ke Bertambah bertahap. Namun, templat utama dapat disebarkan dalam mode lengkap. Jika Anda menyebarkan templat utama dalam mode lengkap, dan templat tertaut atau berlapis menargetkan grup sumber daya yang sama, sumber daya yang disebarkan dalam templat tertaut atau berlapis disertakan dalam evaluasi untuk penyebaran mode lengkap. Gabungan kumpulan sumber daya yang disebarkan dalam templat utama dan templat tertaut atau berlapis dibandingkan dengan sumber daya yang ada di grup sumber daya. Sumber daya apa pun yang tidak disertakan dalam kumpulan gabungan ini akan dihapus.

Jika templat yang ditautkan atau berlapis menargetkan grup sumber daya yang berbeda, penyebaran tersebut menggunakan mode bertambah bertahap. Untuk informasi selengkapnya, lihat Cakupan Penyebaran.

Tip

Kami merekomendasikan Bicep karena menawarkan kemampuan yang sama dengan templat ARM dan sintaksnya lebih mudah digunakan. Untuk mempelajari selengkapnya, lihat modul.

Templat bertumpuk

Untuk membuat templat berlapis, tambahkan sumber daya penyebaran ke templat utama Anda. Dalam properti template, tentukan sintaks templat.

{
  "$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>
        }
      }
    }
  ]
}

Contoh berikut menggunakan akun penyimpanan melalui templat berlapis.

{
  "$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"
            }
          ]
        }
      }
    }
  ]
}

Sumber daya berlapis tidak dapat digunakan dalam templat nama simbolis. Dalam templat berikut, sumber daya akun penyimpanan berlapis tidak dapat menggunakan nama simbolis:

{
  "$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"
            }
          ]
        }
      }
    }
  }
}

Cakupan evaluasi ekspresi dalam templat berlapis

Saat menggunakan templat berlapis, Anda dapat menentukan apakah ekspresi templat dievaluasi dalam cakupan templat induk atau templat berlapis. Cakupan ini menentukan bagaimana parameter, variabel, dan fungsi seperti resourceGroup dan subscription diselesaikan.

Anda mengatur cakupannya melalui properti expressionEvaluationOptions. Secara default, properti expressionEvaluationOptions diatur ke outer, yang berarti menggunakan cakupan templat induk. Atur nilai ke inner agar ekspresi dievaluasi dalam cakupan templat berlapis.

Penting

Untuk languageVersion 2.0, nilai default untuk expressionEvaluationOptions properti adalah inner. Nilai outer diblokir.

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

Catatan

Saat cakupan diatur ke outer, Anda tidak dapat menggunakan fungsi reference di bagian output dari templat berlapis untuk sumber daya yang telah Anda sebarkan di templat berlapis. Untuk mengembalikan nilai sumber daya yang disebarkan dalam template berlapis, gunakan cakupan inner atau konversikan template berlapis Anda menjadi template tertaut.

Templat berikut ini menunjukkan bagaimana ekspresi templat diselesaikan sesuai dengan cakupan. Template ini berisi variabel bernama exampleVar yang didefinisikan dalam templat induk dan templat berlapis. Ia mengembalikan nilai variabel.

{
  "$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]"
    }
  }
}

Nilai perubahan exampleVar bergantung pada nilai properti scope di expressionEvaluationOptions. Tabel berikut ini menunjukkan hasil untuk kedua cakupan.

Cakupan evaluasi Hasil
dalam dari templat berlapis
luar (atau default) dari templat induk

Contoh berikut menyebarkan server SQL dan mengambil rahasia brankas untuk penggunaan kata sandi. Cakupan diatur ke inner karena secara dinamis membuat ID brankas kunci (lihat adminPassword.reference.keyVaultdi templat luarparameters) dan meneruskannya sebagai parameter ke templat berlapis.

{
  "$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": {
  }
}

Berhati-hatilah saat menggunakan nilai parameter aman dalam templat berlapis. Jika Anda mengatur cakupan ke luar, nilai aman disimpan sebagai teks biasa dalam riwayat penyebaran. Pengguna yang melihat templat dalam riwayat penyebaran bisa melihat nilai aman. Sebagai gantinya gunakan cakupan dalam atau tambahkan ke templat induk sumber daya yang membutuhkan nilai aman.

Kutipan berikut menunjukkan nilai mana yang aman dan mana yang tidak aman.

{
  "$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
                }
              }
            }
          ]
        }
      }
    }
  ]
}

Templat tertaut

Untuk menautkan templat, tambahkan sumber daya penyebaran ke templat utama Anda. Di properti templateLink, tentukan URI templat untuk disertakan. Contoh berikut ini menautkan ke templat yang berada di akun penyimpanan.

{
  "$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": {
  }
}

Saat mereferensikan templat yang ditautkan, nilai uri tidak bisa menjadi file lokal atau file yang hanya tersedia di jaringan lokal Anda. Azure Resource Manager harus bisa mengakses templat. Menyediakan nilai URI yang dapat diunduh sebagai HTTP atau HTTPS.

Anda dapat mereferensikan templat menggunakan parameter yang menyertakan HTTP atau HTTPS. Misalnya, pola yang umum adalah dengan menggunakan parameter _artifactsLocation. Anda bisa mengatur templat tertaut dengan ekspresi seperti:

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

Jika Anda menautkan ke templat di GitHub, gunakan URL mentah. Tautan memiliki format: https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json. Untuk mendapatkan tautan mentah, pilih Mentah.

Screenshot of selecting raw URL in GitHub.

Catatan

Untuk menyebarkan templat atau mereferensikan templat tertaut yang disimpan di repositori GitHub privat, lihat solusi kustom yang didokumentasikan dalam Membuat Penawaran Portal Microsoft Azure Kustom yang Aman. Anda dapat membuat Fungsi Azure yang menarik token GitHub keluar dari Azure Key Vault.

Untuk templat yang ditautkan, Anda dapat menumpuk penyebaran nama non-simbolis di dalam templat nama simbolis, atau menumpuk penyebaran nama simbolis di dalam templat non-simbolis, atau menumpuk penyebaran nama simbolis di dalam templat nama simbolis lainnya, atau sebaliknya.

Parameter untuk templat tertaut

Anda dapat menyediakan parameter untuk templat tertaut Anda baik dalam file eksternal atau sebaris. Saat menyediakan file parameter eksternal, gunakan properti parametersLink:

"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"
      }
    }
  }
]

Untuk meneruskan nilai parameter sebaris, gunakan properti parameters.

"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')]"
        }
      }
    }
  }
]

Anda tidak dapat menggunakan parameter sebaris dan tautan pada file parameter. Penyebaran gagal dengan kesalahan ketika keduanya parametersLink dan parameters ditentukan.

Gunakan jalur relatif untuk templat tertaut

Properti relativePath dari Microsoft.Resources/deployments mempermudah pembuatan templat tertaut. Properti ini dapat digunakan untuk menyebarkan templat tertaut jarak jauh di lokasi yang relatif terhadap induknya. Fitur ini mengharuskan semua file templat ditahapkan dan tersedia di URI jarak jauh, seperti akun penyimpanan GitHub atau Azure. Ketika templat utama dipanggil dengan menggunakan URI dari Azure PowerShell atau Azure CLI, URI penyebaran anak adalah kombinasi dari induk dan relativePath.

Catatan

Saat membuat templateSpec, templat apa pun yang direferensikan oleh properti relativePath dikemas dalam sumber daya templateSpec oleh Azure PowerShell atau Azure CLI. Ini tidak memerlukan file untuk ditahapkan. Untuk mengetahui informasi selengkapnya, lihat Membuat spesifikasi templat dengan templat tertaut.

Asumsikan struktur folder seperti ini:

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

Templat berikut ini memperlihatkan cara mainTemplate.json menyebarkan nestedChild.json yang diilustrasikan dalam gambar sebelumnya.

{
  "$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": {}
}

Dalam penyebaran berikut, URI templat tertaut dalam templat sebelumnya adalah 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"

Untuk menyebarkan templat tertaut dengan jalur relatif yang disimpan di akun penyimpanan Azure, gunakan parameter QueryString/query-string untuk menentukan token SAS yang akan digunakan dengan parameter TemplateUri. Parameter ini hanya didukung oleh Azure CLI versi 2.18 atau yang lebih baru dan Azure PowerShell versi 5.4 atau yang lebih baru.

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

Pastikan tidak ada "?" pada jarak antar baris di QueryString. Penyebaran menambahkan satu "?" saat URI dirakit untuk penyebaran.

Spesifikasi templat

Alih-alih mempertahankan templat tertaut Anda pada titik akhir yang dapat diakses, Anda dapat membuat spesifikasi templat yang mengemas templat utama dan templat yang ditautkan ke dalam satu entitas yang dapat Anda sebarkan. Spesifikasi templat adalah sumber daya di langganan Azure Anda. Sumber daya ini memudahkan Anda berbagi templat dengan pengguna di organisasi Anda secara aman. Anda menggunakan kontrol akses berbasis peran Azure (Azure RBAC) untuk memberikan akses ke spesifikasi templat.

Untuk informasi selengkapnya, lihat:

Dependensi

Seperti halnya tipe sumber daya lainnya, Anda dapat mengatur dependensi antara templat terlapis/tertaut. Jika sumber daya dalam satu templat terlapis/tertaut harus digunakan sebelum sumber daya dalam templat terlapis/tertaut kedua, atur templat kedua agar bergantung pada yang pertama.

{
  "$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

Anda tidak perlu menyediakan properti contentVersion untuk properti templateLink atau properti parametersLink. Jika Anda tidak menyediakan contentVersion, versi templat saat ini disebarkan. Jika Anda menyediakan nilai untuk versi konten, nilai tersebut harus cocok dengan versi di templat yang ditautkan; jika tidak, penyebaran akan gagal dengan kesalahan.

Contoh sebelumnya menunjukkan nilai URL yang dikodekan secara permanen untuk link templat. Pendekatan ini mungkin berfungsi untuk templat sederhana, tetapi tidak berfungsi dengan baik untuk sekumpulan besar templat modular. Sebagai gantinya, Anda dapat membuat variabel statis yang menyimpan URL dasar untuk templat utama dan kemudian secara dinamis membuat URL untuk templat yang ditautkan dari URL dasar tersebut. Manfaat dari pendekatan ini adalah Anda dapat dengan mudah memindahkan atau melakukan fork pada templat karena Anda hanya perlu mengubah variabel statis di templat utama. Templat utama melewati URI yang benar di seluruh templat yang sudah tidak berguna.

Contoh berikut menunjukkan cara menggunakan URL dasar untuk membuat dua URL untuk templat yang ditautkan (sharedTemplateUrl dan 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')]"
}

Anda juga dapat menggunakan deployment() untuk mendapatkan URL dasar untuk templat saat ini, dan menggunakannya untuk mendapatkan URL untuk templat lain di lokasi yang sama. Pendekatan ini berguna jika lokasi templat Anda berubah atau Anda ingin menghindari URL yang dikode secara permanen dalam file templat. Properti templateLink hanya dikembalikan saat melakukan penautan ke templat jarak jauh dengan URL. Jika Anda menggunakan templat lokal, properti tersebut tidak tersedia.

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

Pada akhirnya, Anda akan menggunakan variabel dalam properti uri dari properti templateLink.

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

Menggunakan salinan

Untuk membuat beberapa contoh sumber daya dengan templat berlapis, tambahkan elemen copy di tingkat sumber daya Microsoft.Resources/deployments. Atau, jika cakupannya adalah inner, Anda dapat menambahkan salinan dalam templat berlapis.

Contoh templat berikut ini menunjukkan cara menggunakan copy dengan templat berlapis.

"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
            // }
          }
        ]
      }
    }
  }
]

Mendapatkan nilai dari templat tertaut

Untuk mendapatkan nilai output dari templat tertaut, ambil nilai properti dengan sintaks seperti: "[reference('deploymentName').outputs.propertyName.value]".

Saat mendapatkan properti output dari templat tertaut, nama properti tidak boleh menyertakan tanda hubung.

Contoh berikut menunjukkan cara mereferensikan templat tertaut dan mengambil nilai output. Templat tertaut mengembalikan pesan sederhana. Pertama, templat tertaut:

{
  "$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"
    }
  }
}

Template utama menyebarkan template tertaut dan mendapatkan nilai yang dikembalikan. Perhatikan bahwa ia mereferensikan sumber daya penyebaran berdasarkan nama, dan menggunakan nama properti yang dikembalikan oleh templat tertaut.

{
  "$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]"
    }
  }
}

Contoh berikut ini menunjukkan templat yang menggunakan alamat IP publik dan mengembalikan ID sumber daya dari sumber daya Azure untuk IP publik tersebut:

{
  "$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'))]"
    }
  }
}

Untuk menggunakan alamat IP publik dari templat sebelumnya saat menggunakan load balancer, tautkan ke templat dan menyatakan dependensi pada sumber daya Microsoft.Resources/deployments. Alamat IP publik pada load balancer diatur ke nilai output dari templat tertaut.

{
  "$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')]" }
        }
      }
    }
  ]
}

Riwayat penyebaran

Resource Manager memproses setiap templat sebagai penyebaran terpisah dalam riwayat penyebaran. Templat utama dengan tiga templat tertaut atau berlapis muncul dalam riwayat penyebaran sebagai:

Screenshot of deployment history in Azure portal.

Anda dapat menggunakan entri terpisah ini dalam riwayat untuk mengambil nilai output setelah penyebaran. Templat berikut membuat alamat IP publik dan menghasilkan alamat 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]"
    }
  }
}

Templat berikut ini berisi tautan ke templat sebelumnya. Template ini membuat tiga alamat IP publik.

{
  "$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())]"}
        }
      }
    }
  ]
}

Setelah penyebaran, Anda dapat mengambil nilai output dengan skrip PowerShell berikut:

$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)"
}

Atau, skrip Azure CLI dalam shell 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

Mengamankan templat eksternal

Meskipun template tertaut harus tersedia secara eksternal, templat tersebut tidak perlu tersedia secara umum untuk publik. Anda dapat menambahkan templat Anda ke akun penyimpanan pribadi yang hanya dapat diakses oleh pemilik akun penyimpanan. Kemudian, Anda membuat token tanda tangan akses bersama (SAS) untuk mengaktifkan akses selama penyebaran. Anda menambahkan token SAS ke URI untuk templat tertaut. Meskipun token diteruskan sebagai sebuah string aman, URI template tertaut, termasuk token SAS, dicatat dalam operasi penyebaran. Untuk membatasi pencahayaan, atur kedaluwarsa untuk token.

File parameter juga dapat dibatasi untuk diakses melalui token SAS.

Saat ini, Anda tidak dapat menautkan ke templat di akun penyimpanan yang berada di belakang firewall Azure Storage.

Penting

Alih-alih mengamankan templat tertaut Anda dengan token SAS, pertimbangkan untuk membuat spesifikasi templat. Spesifikasi templat menyimpan templat utama dan templat tertautnya dengan aman sebagai sumber daya di langganan Azure Anda. Anda menggunakan Azure RBAC untuk memberikan akses kepada pengguna yang perlu menyebarkan templat.

Contoh berikut ini menunjukkan cara meneruskan token SAS saat menautkan ke templat:

{
  "$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": {
  }
}

Di PowerShell, Anda mendapatkan token untuk kontainer dan menyebarkan templat dengan perintah berikut. Perhatikan bahwa parameter containerSasToken ditentukan dalam templat. Ini bukan parameter dalam perintah 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

Untuk Azure CLI pada shell Bash, Anda mendapatkan token untuk kontainer dan menyebarkan templat dengan kode berikut:

#!/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

Contoh templat

Contoh berikut memperlihatkan penggunaan umum templat tertaut.

Templat utama Templat tertaut Deskripsi
Halo Dunia templat tertaut Mengembalikan string dari templat tertaut.
Load Balancer dengan alamat IP publik templat tertaut Mengembalikan alamat IP publik dari templat tertaut dan menetapkan nilai tersebut dalam penyeimbang muatan.
Beberapa alamat IP templat tertaut Membuat beberapa alamat IP publik dalam templat tertaut.

Langkah berikutnya