استخدام قوالب مرتبطة ومتداخلة عند نشر موارد Azure

لنشر حلول معقدة، يمكنك تقسيم قالب Azure Resource Manager (قالب ARM) إلى العديد من القوالب ذات الصلة، ثم نشرها معاً من خلال قالب رئيسي. يمكن أن تكون القوالب ذات الصلة ملفات منفصلة أو بناء جملة قالب مضمنة داخل القالب الرئيسي. تستخدم هذه المقالة مصطلح القالب المرتبط\ للإشارة إلى ملف قالب منفصل تتم الإشارة إليه عبر ارتباط من القالب الرئيسي. يستخدم مصطلح القالب المتداخل للإشارة إلى بناء جملة القالب المضمن داخل القالب الرئيسي.

بالنسبة للحلول الصغيرة إلى المتوسطة، فإنه من السهل فهم القالب الفردي وصيانته. يمكنك رؤية جميع الموارد والقيم في ملف واحد. بالنسبة للسيناريوهات المتقدمة، تتيح لك القوالب المرتبطة تقسيم الحل إلى مكونات مستهدفة. يمكنك إعادة استخدام هذه القوالب بسهولة لسيناريوهات أخرى.

للحصول على برنامج تعليمي، راجع البرنامج التعليمي: توزيع قالب مرتبط.

إشعار

بالنسبة للقوالب المرتبطة أو المتداخلة، يمكنك فقط تعيين وضع النشر إلى تزايدي. ومع ذلك، يمكن نشر القالب الرئيسي في وضع كامل. إذا قمت بنشر القالب الرئيسي في الوضع الكامل، ويستهدف القالب المرتبط أو المتداخل نفس مجموعة الموارد، يتم تضمين الموارد المنشورة في القالب المرتبط أو المتداخل في التقييم لنشر الوضع الكامل. تتم مقارنة المجموعة المدمجة من الموارد المنشورة في القالب الرئيسي والقوالب المرتبطة أو المتداخلة بالموارد الموجودة في مجموعة الموارد. يتم حذف أي موارد غير مضمنة في هذه المجموعة المدمجة.

إذا كان القالب المرتبط أو المتداخل يستهدف مجموعة موارد مختلفة، يستخدم هذا التوزيع الوضع التزايدي. لمزيد من المعلومات، راجع نطاق النشر.

تلميح

نوصي باستخدام Bicep لأنها تقدم نفس الإمكانات التي توفرها نماذج ARM ولأن البنية أسهل في الاستخدام. لمعرفة المزيد، راجع الوحدات النمطية.

القالب المتداخل

لتداخل قالب، أضف مورد توزيعات إلى القالب الرئيسي. في خاصية template، حدد بناء جملة القالب.

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

المثال التالي بنشر حساب تخزين من خلال قالب متداخلة.

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

لا يمكن استخدام الموارد المتداخلة في قالب اسم رمزي. في القالب التالي، لا يمكن لمورد حساب التخزين المتداخل استخدام الاسم الرمزي:

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

نطاق تقييم التعبير في القوالب المتداخلة

عند استخدام قالب متداخل، يمكنك تحديد ما إذا كان يتم تقييم تعبيرات القالب ضمن نطاق القالب الأصل أو القالب المتداخل. يحدد النطاق كيفية حل المعلمات والمتغيرات والوظائف مثل resourceGroup والاشتراك.

تعيين النطاق من خلال خاصية expressionEvaluationOptions. افتراضياً، يتم تعيين الخاصية expressionEvaluationOptions إلى outer، ما يعني أنها تستخدم نطاق القالب الأصل. تعيين القيمة inner إلى يؤدي التعبيرات إلى تقييم ضمن نطاق القالب المتداخلة.

هام

بالنسبة إلى languageVersion 2.0، القيمة الافتراضية للخاصية expressionEvaluationOptions هي inner. تم حظر القيمة outer .

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

إشعار

عند تعيين النطاق إلى outer، لا يمكنك استخدام reference الدالة في قسم المخرجات في قالب متداخل لمورد قمت بنشره في القالب المتداخل. لإرجاع قيم مورد منشور في قالب متداخل، استخدم inner النطاق أو قم بتحويل القالب المتداخل إلى قالب مرتبط.

يوضح القالب التالي كيفية حل تعبيرات القالب وفقا للنطاق. يحتوي على متغير مسمى exampleVar معرف في كل من القالب الأصل والقالب المتداخل. ترجع قيمة المتغير.

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

قيمة تغييرات exampleVar استناداً إلى قيمة scope الخاصية في expressionEvaluationOptions . يعرض الجدول التالي النتائج لكلا النطاقين.

نطاق التقييم المخرجات
داخلي من قالب متداخل
الخارجي (أو الافتراضي) من القالب الأصل

المثال التالي بتوزيع خادم SQL واسترداد مفتاح سري للخزنة لاستخدامها في كلمة المرور. يتم تعيين النطاق inner لأنه يقوم بإنشاء معرف خزنة المفتاح بشكل ديناميكي (انظر في adminPassword.reference.keyVault القوالب الخارجية) parameters ويمررها كمعلمة إلى القالب المتداخل.

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

كن حذراً عند استخدام قيم المعلمات الآمنة في قالب متداخل. إذا قمت بتعيين النطاق إلى الخارجي، يتم تخزين القيم الآمنة كنص عادي في محفوظات النشر. يمكن أن يرى مستخدم عرض القالب في محفوظات النشر القيم الآمنة. بدلاً من ذلك استخدم النطاق الداخلي أو أضف إلى القالب الأصل الموارد التي تحتاج قيم آمنة.

يظهر المقتطف التالي القيم الآمنة والقيم غير الآمنة.

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

القالب المرتبط

لربط قالب، أضف مورد نشر إلى القالب الرئيسي. في خاصية templateLink، حدد URI للقالب لتضمينه. يرتبط المثال التالي بقالب موجود في حساب تخزين.

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

عند الرجوع إلى قالب مرتبط، لا يمكن أن تكون قيمة uri ملف محلي أو ملف متوفر فقط على الشبكة المحلية. يجب أن تكون Azure Resource Manager قادرة على الوصول إلى القالب. توفير قيمة URI التي يمكن تنزيلها ك HTTP أو HTTPS.

يمكنك الرجوع إلى قوالب باستخدام معلمات تتضمن HTTP أو HTTPS. على سبيل المثال، نمط شائع هو استخدام معلمة _artifactsLocation. يمكنك تعيين القالب المرتبط بتعبير مثل:

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

إذا كنت تقوم بالارتباط بقالب في GitHub، فاستخدم عنوان URL الأولي. يحتوي الارتباط على التنسيق: https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-with-templates/quickstart-template/azuredeploy.json. للحصول على الرابط الخام، حدد خام.

Screenshot of selecting raw URL in GitHub.

إشعار

لتوزيع قالب أو الرجوع إلى قالب مرتبط مخزّن في مستودع GitHub خاص، راجع الحل المخصص الموثق في إنشاء عرض مدخل Microsoft Azure مخصص وآمن. يمكنك إنشاء Azure Function التي تسحب رمز GitHub المميز من Azure Key Vault.

بالنسبة للقوالب المرتبطة، يمكنك تضمين نشر اسم غير رمزي داخل قالب اسم رمزي، أو تضمين نشر اسم رمزي داخل قالب غير رمزي، أو تداخل نشر اسم رمزي داخل قالب اسم رمزي آخر، أو العكس بالعكس.

معلمات القالب المرتبط

يمكنك توفير معلمات القالب المرتبط إما في ملف خارجي أو مضمن. عند توفير ملف معلمة خارجية، استخدم خاصية 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"
      }
    }
  }
]

لتمرير قيم المعلمات المضمنة، استخدم خاصية 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')]"
        }
      }
    }
  }
]

لا يمكنك استخدام كل من المعلمات المضمنة والارتباط بملف معلمة. فشل النشر مع وجود خطأ عند كليهما parametersLink وparameters يتم تحديدهما.

استخدام المسار النسبي للقوالب المرتبطة

خاصية relativePathالخاصة بـ Microsoft.Resources/deployments تجعل من السهل تأليف قوالب مرتبطة. يمكن استخدام هذه الخاصية لنشر قالب مرتبط بعيد في موقع نسبة إلى الأصل. تتطلب هذه الميزة جميع ملفات القالب إلى مرحلي والمتوفرة في URI بعيد، مثل حساب تخزين GitHub أو Azure. عند استدعاء القالب الرئيسي باستخدام URI من Azure PowerShell أو Azure CLI، URI النشر التابعة هو تركيبة من الأصل وRELATIVEPath.

إشعار

عند إنشاء templateSpec، يتم حزم أي قوالب المشار إليها من قِبَل relativePath الخاصية في مورد قوالب من قِبَل Azure PowerShell أو Azure CLI. لا يتطلب الملفات إلى مرحلي. لمزيد من المعلومات، راجع إنشاء مواصفات قالب مع قوالب مرتبطة.

افترض بنية مجلد مثل هذا:

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

يوضح القالب التالي كيفية نشرmainTemplate.jsعلىnestedChild.js موضحة في الصورة السابقة.

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

في النشر التالي، يكون URI للقالب المرتبط في القالب السابق هو 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"

لنشر قوالب مرتبطة ذات مسار نسبي مخزن في حساب تخزين Azure، استخدم معلمة QueryString/query-string لتحديد الرمز المميز SAS لاستخدامه مع المعلمة TemplateUri. هذه المعلمة معتمدة فقط بواسطة الإصدار 2.18 من Azure CLI أو إصدار أحدث وإصدار Azure PowerShell 5.4 أو إصدار أحدث.

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

تأكد من عدم وجود أي إعادة "؟" في QueryString. النشر يضيف واحدة عند تجميع URI عمليات النشر.

مواصفات القالب

بدلاً من الحفاظ على القوالب المرتبطة عند نقطة نهاية يمكن الوصول إليها، يمكنك إنشاء مواصفات قالب تقوم بتعبئة القالب الرئيسي والقوالب المرتبطة به في كيان واحد يمكنك نشره. المواصفات القالب هو مورد في اشتراك Azure الخاص بك. فهو يسهل مشاركة القالب بأمان مع المستخدمين في مؤسستك. يمكنك استخدام التحكم في الوصول المستند إلى دور Azure (Azure RBAC) لمنح حق الوصول إلى مواصفات القالب.

لمزيد من المعلومات، راجع:

التبعيات

كما هو الحال مع أنواع الموارد الأخرى، يمكنك تعيين التبعيات بين القوالب المرتبطة/المتداخلة. إذا كان يجب توزيع الموارد في قالب مرتبط/متداخل واحد قبل الموارد في قالب مرتبط/متداخل ثانٍ، فقم بتعيين القالب الثاني الذي يعتمد على الأول.

{
  "$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 للخاصية templateLink أو parametersLink. إذا لم توفر contentVersion، يتم نشر الإصدار الحالي من القالب. إذا قمت بتوفير قيمة لإصدار المحتوى، فيجب أن تتطابق مع الإصدار الموجود في القالب المرتبط؛ وإلا، يفشل النشر مع وجود خطأ.

أظهرت الأمثلة السابقة قيم URL ذات الترميز الثابت لارتباطات القالب. قد يعمل هذا النهج لقالب بسيط، ولكنه لا يعمل بشكل جيد لمجموعة كبيرة من القوالب المعيارية. بدلاً من ذلك، يمكنك إنشاء متغير ثابت يخزن عنوان URL أساسي للقالب الرئيسي ثم إنشاء عناوين URL للقوالب المرتبطة من عنوان URL الأساسي هذا بشكل حيوي. الفائدة من هذا الأسلوب هو أنه يمكنك بسهولة نقل أو شوكة القالب لأنك تحتاج إلى تغيير المتغير الثابت فقط في القالب الرئيسي. يمرر القالب الرئيسي URI الصحيح في جميع أنحاء القالب المتحلل.

يوضح المثال التالي كيفية استخدام عنوان URL أساسي لإنشاء محددي مواقع المعلومات للقوالب المرتبطة ( sharedTemplateUrl و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')]"
}

يمكنك أيضاً استخدام النشر() للحصول على عنوان URL الأساسي للقالب الحالي، واستخدام ذلك للحصول على عنوان URL للقوالب الأخرى في نفس الموقع. يفيد هذا الأسلوب إذا تغير موقع القالب أو كنت تريد تجنب عناوين URL الثابتة في ملف القالب. يتم إرجاع الخاصية templateLink فقط عند الارتباط بقالب بعيد مع محدد موقع معلومات( URL). إذا كنت تستخدم قالب محلي، فلن تتوفر هذه الخاصية.

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

في نهاية المطاف، يمكنك استخدام المتغير في خاصيةuri من خاصية templateLink.

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

استخدام نسخة

لإنشاء مثيلات متعددة من مورد مع قالب متداخلة إضافة copy العنصر على مستوى مورد Microsoft.Resources/deployments. أو، إذا كان النطاق inner، فيمكنك إضافة النسخة داخل القالب المتداخل.

يوضح قالب المثال التالي كيفية استخدام copy مع قالب متداخل.

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

الحصول على قيم من قالب مرتبط

للحصول على قيمة إخراج من قالب مرتبط، استرجع قيمة الخاصية باستخدام بناء الجملة مثل: "[reference('deploymentName').outputs.propertyName.value]".

عند الحصول على خاصية إخراج من قالب مرتبط، يجب أن لا يتضمن اسم الخاصية شرطة.

توضح الأمثلة التالية كيفية الرجوع إلى قالب مرتبط واسترداد قيمة إخراج. إرجاع القالب المرتبط رسالة بسيطة. أولاً، القالب المرتبط:

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

يقوم القالب الرئيسي بنشر القالب المرتبط ويحصل على القيمة التي تم إرجاعها. لاحظ أنه يشير إلى مورد التوزيع حسب الاسم، ويستخدم اسم الخاصية التي تم إرجاعها بواسطة القالب المرتبط.

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

يظهر المثال التالي قالب نشر عنوان IP عام وإرجاع معرف المورد مورد Azure لهذا 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'))]"
    }
  }
}

لاستخدام عنوان IP العام من القالب السابق عند نشر موازن تحميل، قم بالارتباط بالقالب وتعريف تبعية على Microsoft.Resources/deployments المورد. يتم تعيين عنوان IP العام على موازن التحميل إلى قيمة الإخراج من القالب المرتبط.

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

تاريخ التوزيع

إدارة الموارد بمعالجة كل قالب بصورة نشر منفصلة في محفوظات التوزيع. يظهر قالب رئيسي مع ثلاثة قوالب مرتبطة أو متداخلة في محفوظات النشر كما يلي:

Screenshot of deployment history in Azure portal.

يمكنك استخدام هذه الإدخالات منفصلة في المحفوظات لاسترداد قيم الإخراج بعد النشر. ينشئ القالب التالي عنوان IP عام ويخرج عنوان 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]"
    }
  }
}

يرتبط القالب التالي بالقالب السابق. يقوم بإنشاء ثلاثة عناوين 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())]"}
        }
      }
    }
  ]
}

بعد النشر، يمكنك استرداد قيم الإخراج مع البرنامج النصي 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)"
}

أو، البرنامج النصي CLI Azure في 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

تأمين قالب خارجي

على الرغم من أن القالب المرتبط يجب أن يكون متوفراً خارجيا، إلا أنه لا يحتاج إلى أن يكون متاحا بشكل عام للجمهور. يمكنك إضافة القالب إلى حساب تخزين خاص يمكن لمالك حساب التخزين الوصول إليه فقط. ثم إنشاء رمز مميز توقيع وصول مشترك (SAS) لتمكين الوصول أثناء النشر. إضافة الرمز المميز SAS إلى URI للقالب المرتبط. على الرغم من أن يتم تمرير الرمز المميز في كسلسلة آمنة، يتم تسجيل URI القالب المرتبط، بما في ذلك الرمز المميز SAS، في عمليات النشر. للحد من التعرض، قم بتعيين انتهاء صلاحية الرمز المميز.

يمكن أيضاً أن يكون ملف المعلمة محدودة للوصول من خلال رمز SAS المميز.

حالياً، لا يمكنك الارتباط بقالب في حساب تخزين خلف جدار حماية تخزين Azure.

هام

بدلاً من تأمين القالب المرتبط باستخدام رمز SAS، فكر في إنشاء مواصفات قالب.تخزن مواصفات القالب بشكل آمن القالب الرئيسي والقوالب المرتبطة به كمورد في اشتراك Azure. يمكنك استخدام AZURE RBAC لمنح حق الوصول إلى المستخدمين الذين يحتاجون إلى نشر القالب.

يوضح المثال التالي كيفية تمرير رمز SAS المميز عند الارتباط بقالب:

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

في PowerShell، يمكنك الحصول على رمز مميز للحاوية ونشر القوالب مع الأوامر التالية. لاحظ أن معلمة containerSasToken مُعرَّفة في القالب. إنها ليست معلمة في الأمر 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

ل Azure CLI في Bash shell، تحصل على رمز مميز للحاوية ونشر القوالب مع التعليمات البرمجية التالية:

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

قوالب المثال

تظهر الأمثلة التالية الاستخدامات الشائعة للقوالب المرتبطة.

القالب الرئيسي القالب المرتبط ‏‏الوصف
Hello, world القالب المرتبط يُرجِع سلسلة من قالب مرتبط.
تحميل موازن مع عنوان IP عام القالب المرتبط يرجع عنوان IP العام من قالب مرتبط ويقوم بتعيين القيمة في موازن التحميل.
عناوين IP متعددة القالب المرتبط إنشاء عدة عناوين IP عامة في قالب مرتبط.

الخطوات التالية