البرنامج التعليمي: توزيع قالب مرتبط

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

المتطلبات الأساسية

نوصي بإكمال البرنامج التعليمي حول المخرجات، لكنه ليس إلزامياً.

راجع القالب

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

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 11,
      "metadata": {
        "description": "Specify a project name that is used to generate resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "storageSKU": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Standard_ZRS",
        "Premium_LRS",
        "Premium_ZRS",
        "Standard_GZRS",
        "Standard_RAGZRS"
      ],
      "metadata": {
        "description": "Specify the storage account type."
      }
    },
    "linuxFxVersion": {
      "type": "string",
      "defaultValue": "php|7.0",
      "metadata": {
        "description": "Specify the Runtime stack of current web app"
      }
    }
  },
  "variables": {
    "storageAccountName": "[format('{0}{1}', parameters('projectName'), uniqueString(resourceGroup().id))]",
    "webAppName": "[format('{0}WebApp', parameters('projectName'))]",
    "appServicePlanName": "[format('{0}Plan', parameters('projectName'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-01-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('storageSKU')]"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    },
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2022-09-01",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "B1",
        "tier": "Basic",
        "size": "B1",
        "family": "B",
        "capacity": 1
      },
      "kind": "linux",
      "properties": {
        "perSiteScaling": false,
        "reserved": true,
        "targetWorkerCount": 0,
        "targetWorkerSizeId": 0
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2022-09-01",
      "name": "[variables('webAppName')]",
      "location": "[parameters('location')]",
      "kind": "app",
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "siteConfig": {
          "linuxFxVersion": "[parameters('linuxFxVersion')]"
        }
      },
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ]
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').primaryEndpoints]"
    }
  }
}

إنشاء قالب مرتبط

يمكنك فصل مورد حساب التخزين في قالب مرتبط:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "metadata": {
        "description": "Specify the storage account name."
      }
    },
    "location": {
      "type": "string",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "storageSKU": {
      "type": "string",
      "defaultValue": "Standard_LRS",
      "allowedValues": [
        "Standard_LRS",
        "Standard_GRS",
        "Standard_RAGRS",
        "Standard_ZRS",
        "Premium_LRS",
        "Premium_ZRS",
        "Standard_GZRS",
        "Standard_RAGZRS"
      ],
      "metadata": {
        "description": "Specify the storage account type."
      }
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-01-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('storageSKU')]"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference(parameters('storageAccountName')).primaryEndpoints]"
    }
  }
}

القالب التالي هو القالب الرئيسي. يوضح العنصر Microsoft.Resources/deployments المميز كيفية استدعاء قالب مرتبط. لا يمكن تخزين القالب المرتبط كملف محلي أو ملف متوفر فقط على الشبكة المحلية. يمكنك إما توفير قيمة URI للقالب المرتبط الذي يتضمن إما HTTP أو HTTPS، أو استخدام خاصية relativePath لتوزيع قالب مرتبط عن بُعد في موقع متعلق بالقالب الأصلي. أحد الخيارات هو وضع كل من القالب الرئيسي والقالب المرتبط في حساب تخزين.

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "minLength": 3,
      "maxLength": 11,
      "metadata": {
        "description": "Specify a project name that is used to generate resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify a location for the resources."
      }
    },
    "linuxFxVersion": {
      "type": "string",
      "defaultValue": "php|7.0",
      "metadata": {
        "description": "The Runtime stack of current web app"
      }
    }
  },
  "variables": {
    "storageAccountName": "[concat(parameters('projectName'), uniqueString(resourceGroup().id))]",
    "webAppName": "[concat(parameters('projectName'), 'WebApp')]",
    "appServicePlanName": "[concat(parameters('projectName'), 'Plan')]"
  },
  "resources": [
    {
      "name": "linkedTemplate",
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2022-09-01",
      "properties": {
        "mode": "Incremental",
        "templateLink": {
          "relativePath": "linkedStorageAccount.json"
        },
        "parameters": {
          "storageAccountName": {
            "value": "[variables('storageAccountName')]"
          },
          "location": {
            "value": "[parameters('location')]"
          }
        }
      }
    },
    {
      "type": "Microsoft.Web/serverfarms",
      "apiVersion": "2022-09-01",
      "name": "[variables('appServicePlanName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "B1",
        "tier": "Basic",
        "size": "B1",
        "family": "B",
        "capacity": 1
      },
      "kind": "linux",
      "properties": {
        "perSiteScaling": false,
        "reserved": true,
        "targetWorkerCount": 0,
        "targetWorkerSizeId": 0
      }
    },
    {
      "type": "Microsoft.Web/sites",
      "apiVersion": "2022-09-01",
      "name": "[variables('webAppName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]"
      ],
      "kind": "app",
      "properties": {
        "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]",
        "siteConfig": {
          "linuxFxVersion": "[parameters('linuxFxVersion')]"
        }
      }
    }
  ],
  "outputs": {
    "storageEndpoint": {
      "type": "object",
      "value": "[reference('linkedTemplate').outputs.storageEndpoint.value]"
    }
  }
}

تخزين القالب المرتبط

يتم تخزين كل من القالب الرئيسي والقالب المرتبط في GitHub:

يقوم البرنامج النصي PowerShell التالي بإنشاء حساب تخزين وإنشاء حاوية ونسخ النموذجين من مستودع GitHub إلى الحاوية. هذان القالبان هما:

حدد Try-it لفتح Cloud Shell، وحدد نسخ لنسخ البرنامج النصي PowerShell، وانقر بزر الماوس الأيمن فوق جزء shell للصق البرنامج النصي:

هام

يجب أن تكون أسماء حسابات التخزين فريدة، ويتراوح طولها بين 3 و24 حرفاً، وأن تستخدم أرقاماً وأحرفاً إنجليزية صغيرة فقط. يدمج المتغير storageAccountName الخاص بنموذج النموذج بين 11 حرفاً بحد أقصى للمعلمة projectName وقيمة سلسلة فريدة مكونة من 13 حرفاً.

$projectName = Read-Host -Prompt "Enter a project name:"   # This name is used to generate names for Azure resources, such as storage account name.
$location = Read-Host -Prompt "Enter a location (i.e. centralus)"

$resourceGroupName = $projectName + "rg"
$storageAccountName = $projectName + "store"
$containerName = "templates" # The name of the Blob container to be created.

$mainTemplateURL = "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-deployment/linked-template/azuredeploy.json"
$linkedTemplateURL = "https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/get-started-deployment/linked-template/linkedStorageAccount.json"

$mainFileName = "azuredeploy.json" # A file name used for downloading and uploading the main template.Add-PSSnapin
$linkedFileName = "linkedStorageAccount.json" # A file name used for downloading and uploading the linked template.

# Download the templates
Invoke-WebRequest -Uri $mainTemplateURL -OutFile "$home/$mainFileName"
Invoke-WebRequest -Uri $linkedTemplateURL -OutFile "$home/$linkedFileName"

# Create a resource group
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Create a storage account
$storageAccount = New-AzStorageAccount `
    -ResourceGroupName $resourceGroupName `
    -Name $storageAccountName `
    -Location $location `
    -SkuName "Standard_LRS"

$context = $storageAccount.Context

# Create a container
New-AzStorageContainer -Name $containerName -Context $context -Permission Container

# Upload the templates
Set-AzStorageBlobContent `
    -Container $containerName `
    -File "$home/$mainFileName" `
    -Blob $mainFileName `
    -Context $context

Set-AzStorageBlobContent `
    -Container $containerName `
    -File "$home/$linkedFileName" `
    -Blob $linkedFileName `
    -Context $context

Write-Host "Press [ENTER] to continue ..."

نشر القالب

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

إذا لم تُنشأ مجموعة الموارد، فراجع إنشاء مجموعة موارد.

ملاحظة

في التعليمات البرمجية لـ Azure CLI أدناه، فإن المعلمة date-d تعد وسيطة غير صالحة في macOS. لذا، بالنسبة لمستخدمي macOS، لإضافة ساعتين إلى الوقت الحالي في المحطة الطرفية على macOS، يجب عليك استخدام -v+2H.


$projectName = Read-Host -Prompt "Enter the same project name:"   # This name is used to generate names for Azure resources, such as storage account name.

$resourceGroupName="${projectName}rg"
$storageAccountName="${projectName}store"
$containerName = "templates"

$key = (Get-AzStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName).Value[0]
$context = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $key

$mainTemplateUri = $context.BlobEndPoint + "$containerName/azuredeploy.json"
$sasToken = New-AzStorageContainerSASToken `
    -Context $context `
    -Container $containerName `
    -Permission r `
    -ExpiryTime (Get-Date).AddHours(2.0)
$newSas = $sasToken.substring(1)


New-AzResourceGroupDeployment `
  -Name DeployLinkedTemplate `
  -ResourceGroupName $resourceGroupName `
  -TemplateUri $mainTemplateUri `
  -QueryString $newSas `
  -projectName $projectName `
  -verbose

Write-Host "Press [ENTER] to continue ..."

تنظيف الموارد

قم بتنظيف الموارد التي قمت بنشرها عن طريق حذف مجموعة الموارد.

  1. من مدخل Azure، حدد مجموعة الموارد من القائمة اليمنى.
  2. أدخل اسم مجموعة الموارد في الحقل Filter by name.
  3. حدد اسم مجموعة الموارد.
  4. حدد Delete resource group من القائمة.

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

تعلمت كيفية توزيع قالب مرتبط. في البرنامج التعليمي التالي، يمكنك معرفة كيفية إنشاء مسار DevOps لتوزيع قالب.