在 ARM 範本中設定部署指令碼的開發環境

了解如何使用部署指令碼映像,來建立可用來開發和測試 ARM 範本部署指令碼的開發環境。 您可以建立 Azure 容器執行個體,或使用 Docker (英文)。 此文章將涵蓋這兩個選項。

重要

部署指令碼記錄可包含寫入至 Write-Host、echo、stdout 和 stderr 的內容。 你可以透過 /deploymentScripts/logs 端點或相關 API 取得這些資訊。 不要將敏感資訊寫入腳本輸出,包括存取權杖、持有權杖、SAS 權杖、連線字串、憑證或其他秘密。 腳本作者負責確保部署腳本日誌不會洩露敏感資訊。

必要條件

Azure PowerShell 容器

如果您沒有 Azure PowerShell 部署指令碼,您可以使用下列內容來建立 hello.ps1 檔案:

param([string] $name)
$output = 'Hello {0}' -f $name
Write-Output $output
$DeploymentScriptOutputs = @{}
$DeploymentScriptOutputs['text'] = $output

Azure CLI 容器

針對 Azure CLI 容器映像,您可以使用下列內容來建立 hello.sh 檔案:

FIRSTNAME=$1
LASTNAME=$2
OUTPUT="{\"name\":{\"displayName\":\"$FIRSTNAME $LASTNAME\",\"firstName\":\"$FIRSTNAME\",\"lastName\":\"$LASTNAME\"}}"
echo -n "Hello "
echo $OUTPUT | jq -r '.name.displayName'

注意

當您執行 Azure CLI 部署指令碼時,名為 AZ_SCRIPTS_OUTPUT_PATH 的環境變數會儲存指令碼輸出檔案的位置。 此環境變數無法在開發環境容器中使用。 如需深入了解如何處理 Azure CLI 的輸出,請參閱 處理 CLI 指令碼的輸出。

使用 Azure PowerShell 建立容器執行個體

若要在電腦上撰寫指令碼,您必須建立儲存體帳戶,並將儲存體帳戶掛接到容器執行個體。 如此一來,您就可以將指令碼上傳至儲存體帳戶,並在容器執行個體上執行指令碼。

注意

您建立來測試指令碼的儲存體帳戶,與部署指令碼服務用來執行指令碼的儲存體帳戶不同。 部署指令碼服務會在每次執行時,建立唯一的名稱來作為檔案共用。

建立 Azure PowerShell 容器執行個體

下列 Azure Resource Manager 範本 (ARM 範本) 會建立容器執行個體和檔案共用,然後將檔案共用掛接到容器映像。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "metadata": {
        "description": "Specify a project name that is used for generating resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify the resource location."
      }
    },
    "containerImage": {
      "type": "string",
      "defaultValue": "mcr.microsoft.com/azuredeploymentscripts-powershell:az9.7",
      "metadata": {
        "description": "Specify the container image."
      }
    },
    "mountPath": {
      "type": "string",
      "defaultValue": "/mnt/azscripts/azscriptinput",
      "metadata": {
        "description": "Specify the mount path."
      }
    }
  },
  "variables": {
    "storageAccountName": "[toLower(format('{0}store', parameters('projectName')))]",
    "fileShareName": "[format('{0}share', parameters('projectName'))]",
    "containerGroupName": "[format('{0}cg', parameters('projectName'))]",
    "containerName": "[format('{0}container', parameters('projectName'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2025-06-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {
        "accessTier": "Hot"
      }
    },
    {
      "type": "Microsoft.Storage/storageAccounts/fileServices/shares",
      "apiVersion": "2025-06-01",
      "name": "[format('{0}/default/{1}', variables('storageAccountName'), variables('fileShareName'))]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2025-09-01",
      "name": "[variables('containerGroupName')]",
      "location": "[parameters('location')]",
      "properties": {
        "containers": [
          {
            "name": "[variables('containerName')]",
            "properties": {
              "image": "[parameters('containerImage')]",
              "resources": {
                "requests": {
                  "cpu": 1,
                  "memoryInGB": "[json('1.5')]"
                }
              },
              "ports": [
                {
                  "protocol": "TCP",
                  "port": 80
                }
              ],
              "volumeMounts": [
                {
                  "name": "filesharevolume",
                  "mountPath": "[parameters('mountPath')]"
                }
              ],
              "command": [
                "/bin/sh",
                "-c",
                "pwsh -c 'Start-Sleep -Seconds 1800'"
              ]
            }
          }
        ],
        "osType": "Linux",
        "volumes": [
          {
            "name": "filesharevolume",
            "azureFile": {
              "readOnly": false,
              "shareName": "[variables('fileShareName')]",
              "storageAccountName": "[variables('storageAccountName')]",
              "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2023-01-01').keys[0].value]"
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    }
  ]
}

掛接路徑的預設值為 /mnt/azscripts/azscriptinput。 這是在容器執行個體中掛接至檔案共用的路徑。

範本中指定的預設容器映像是 mcr.microsoft.com/azuredeploymentscripts-powershell:az9.7。 請參閱所有支援的 Azure PowerShell 版本清單。

此範本會在 1,800 秒之後暫止容器執行個體。 在容器執行個體進入終止狀態且工作階段結束之前,您有 30 分鐘的時間。

若要部署範本:

$projectName = Read-Host -Prompt "Enter a project name that is used to generate resource names"
$location = Read-Host -Prompt "Enter the location (i.e. centralus)"
$templateFile = Read-Host -Prompt "Enter the template file path and file name"
$resourceGroupName = "${projectName}rg"

New-AzResourceGroup -Location $location -name $resourceGroupName
New-AzResourceGroupDeployment -resourceGroupName $resourceGroupName -TemplateFile $templatefile -projectName $projectName

上傳部署指令碼

將部署指令碼上傳至儲存體帳戶。 以下是 PowerShell 指令碼範例:

$projectName = Read-Host -Prompt "Enter the same project name that you used earlier"
$fileName = Read-Host -Prompt "Enter the deployment script file name with the path"

$resourceGroupName = "${projectName}rg"
$storageAccountName = "${projectName}store"
$fileShareName = "${projectName}share"

$context = (Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName).Context
Set-AzStorageFileContent -Context $context -ShareName $fileShareName -Source $fileName -Force

您也可以使用 Azure 入口網站或 Azure CLI 來上傳檔案。

測試部署指令碼

  1. 在 Azure 入口網站中,開啟您部署容器執行個體和儲存體帳戶所在的資源群組。

  2. 開啟容器群組。 預設容器群組名稱是附加 cg 的專案名稱。 此容器執行個體處於執行中狀態。

  3. 在資源功能表中,選取 [容器]。 容器執行個體名稱是附加 container 的專案名稱。

    Azure 入口網站中部署指令碼的 [連線容器執行個體] 選項螢幕擷圖。

  4. 選取 [連線],然後選取 [連線]。 如果您無法連線到容器執行個體,請將容器群組重新啟動,然後再試一次。

  5. 在主控台窗格中,執行下列命令:

    cd /mnt/azscripts/azscriptinput
    ls
    pwsh ./hello.ps1 "John Dole"
    

    輸出為 Hello John Dole。

    主控台中顯示的部署指令碼連線容器執行個體測試輸出的螢幕擷取畫面。

使用 Azure CLI 容器執行個體

若要在電腦上撰寫指令碼,請建立儲存體帳戶,並將儲存體帳戶掛接到容器執行個體。 接著,您可以將指令碼上傳至儲存體帳戶,並在容器執行個體上執行指令碼。

注意

您建立來測試指令碼的儲存體帳戶,與部署指令碼服務用來執行指令碼的儲存體帳戶不同。 部署指令碼服務會在每次執行時,建立唯一的名稱來作為檔案共用。

建立 Azure CLI 容器執行個體

下列 ARM 範本會建立容器執行個體和檔案共用,然後將檔案共用掛接到容器映像:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "projectName": {
      "type": "string",
      "metadata": {
        "description": "Specify a project name that is used for generating resource names."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify the resource location."
      }
    },
    "containerImage": {
      "type": "string",
      "defaultValue": "mcr.microsoft.com/azure-cli:2.9.1",
      "metadata": {
        "description": "Specify the container image."
      }
    },
    "mountPath": {
      "type": "string",
      "defaultValue": "/mnt/azscripts/azscriptinput",
      "metadata": {
        "description": "Specify the mount path."
      }
    }
  },
  "variables": {
    "storageAccountName": "[toLower(format('{0}store', parameters('projectName')))]",
    "fileShareName": "[format('{0}share', parameters('projectName'))]",
    "containerGroupName": "[format('{0}cg', parameters('projectName'))]",
    "containerName": "[format('{0}container', parameters('projectName'))]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2025-06-01",
      "name": "[variables('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {
        "accessTier": "Hot"
      }
    },
    {
      "type": "Microsoft.Storage/storageAccounts/fileServices/shares",
      "apiVersion": "2025-06-01",
      "name": "[format('{0}/default/{1}', variables('storageAccountName'), variables('fileShareName'))]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    },
    {
      "type": "Microsoft.ContainerInstance/containerGroups",
      "apiVersion": "2025-09-01",
      "name": "[variables('containerGroupName')]",
      "location": "[parameters('location')]",
      "properties": {
        "containers": [
          {
            "name": "[variables('containerName')]",
            "properties": {
              "image": "[parameters('containerImage')]",
              "resources": {
                "requests": {
                  "cpu": 1,
                  "memoryInGB": "[json('1.5')]"
                }
              },
              "ports": [
                {
                  "protocol": "TCP",
                  "port": 80
                }
              ],
              "volumeMounts": [
                {
                  "name": "filesharevolume",
                  "mountPath": "[parameters('mountPath')]"
                }
              ],
              "command": [
                "/bin/bash",
                "-c",
                "echo hello; sleep 1800"
              ]
            }
          }
        ],
        "osType": "Linux",
        "volumes": [
          {
            "name": "filesharevolume",
            "azureFile": {
              "readOnly": false,
              "shareName": "[variables('fileShareName')]",
              "storageAccountName": "[variables('storageAccountName')]",
              "storageAccountKey": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2022-09-01').keys[0].value]"
            }
          }
        ]
      },
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
      ]
    }
  ]
}

掛接路徑的預設值為 /mnt/azscripts/azscriptinput。 這是在容器執行個體中掛接至檔案共用的路徑。

範本中指定的預設容器映像是 mcr.microsoft.com/azure-cli:2.9.1。 請參閱支援的 Azure CLI 版本清單。

重要

部署指令碼會使用 Microsoft Container Registry (MCR) 中的可用 CLI 映像。 對 CLI 映像進行部署指令碼的認證大約需要一個月的時間。 請勿使用在 30 天內發行的 CLI 版本。 若要尋找映像的發行日期,請參閱 Azure CLI 版本資訊。 如果您使用不支援的版本,錯誤訊息就會列出支援的版本。

此範本會在 1,800 秒之後暫止容器執行個體。 在容器執行個體進入終端狀態且工作階段結束之前,您有 30 分鐘的時間。

若要部署範本:

$projectName = Read-Host -Prompt "Enter a project name that is used to generate resource names"
$location = Read-Host -Prompt "Enter the location (i.e. centralus)"
$templateFile = Read-Host -Prompt "Enter the template file path and file name"
$resourceGroupName = "${projectName}rg"

New-AzResourceGroup -Location $location -name $resourceGroupName
New-AzResourceGroupDeployment -resourceGroupName $resourceGroupName -TemplateFile $templatefile -projectName $projectName

上傳部署指令碼

將部署指令碼上傳至儲存體帳戶。 以下是 PowerShell 範例:

$projectName = Read-Host -Prompt "Enter the same project name that you used earlier"
$fileName = Read-Host -Prompt "Enter the deployment script file name with the path"

$resourceGroupName = "${projectName}rg"
$storageAccountName = "${projectName}store"
$fileShareName = "${projectName}share"

$context = (Get-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName).Context
Set-AzStorageFileContent -Context $context -ShareName $fileShareName -Source $fileName -Force

您也可以使用 Azure 入口網站或 Azure CLI 來上傳檔案。

測試部署指令碼

  1. 在 Azure 入口網站中,開啟您部署容器執行個體和儲存體帳戶所在的資源群組。

  2. 開啟容器群組。 預設容器群組名稱是附加 cg 的專案名稱。 此容器執行個體顯示為執行中狀態。

  3. 在資源功能表中,選取 [容器]。 容器執行個體名稱是附加 container 的專案名稱。

    Azure 入口網站中部署指令碼的 [連線容器執行個體] 選項螢幕擷圖。

  4. 選取 [連線],然後選取 [連線]。 如果您無法連線到容器執行個體,請將容器群組重新啟動,然後再試一次。

  5. 在主控台窗格中,執行下列命令:

    cd /mnt/azscripts/azscriptinput
    ls
    ./hello.sh John Dole
    

    輸出為 Hello John Dole。

    主控台中顯示的部署指令碼容器執行個體測試輸出的螢幕擷取畫面。

使用 Docker

您可以使用預先設定的 Docker 容器映像作為部署指令碼開發環境。 若要安裝 Docker,請參閱取得 docker (英文)。 您也需要設定檔案共用,將包含部署指令碼的目錄掛接到 Docker 容器。

  1. 將部署指令碼容器映像提取到本機電腦:

    docker pull mcr.microsoft.com/azuredeploymentscripts-powershell:az4.3
    

    此範例使用 PowerShell 4.3.0 版。

    從 MCR 拉取 CLI 映像檔:

    docker pull mcr.microsoft.com/azure-cli:2.0.80
    

    此範例使用 CLI 2.0.80 版。 部署指令碼會使用這裡找到的預設 CLI 容器映像。

  2. 在本機執行 Docker 映像。

    docker run -v <host drive letter>:/<host directory name>:/data -it mcr.microsoft.com/azuredeploymentscripts-powershell:az4.3
    

    以共用磁碟機上的現有資料夾取代 <主機磁碟機代號> 和 <主機目錄名稱>。 其會將資料夾對應至容器中的 /data 資料夾。 例如,若要對應 D:\docker:

    docker run -v d:/docker:/data -it mcr.microsoft.com/azuredeploymentscripts-powershell:az4.3
    

    -it 表示讓容器映像保持運作。

    CLI 範例:

    docker run -v d:/docker:/data -it mcr.microsoft.com/azure-cli:2.0.80
    
  3. 下列螢幕擷取畫面顯示當您在共用磁碟機中有 helloworld.ps1 檔案時,如何執行 PowerShell 指令碼。

    使用 Docker 命令的 Resource Manager 範本部署指令碼的螢幕擷取畫面。

成功測試指令碼之後,您可以使用該指令碼作為範本中的部署指令碼。

下一步

在本文中,您已了解如何使用部署指令碼。 逐步解說部署指令碼教學課程: