如何通过 ARM 模板设置 Azure Batch 池容器配置?
How to set up Azure Batch pool container configuration via ARM template?
我们正在使用 Azure Batch,我们需要在虚拟机上使用 Windows Docker 个容器。
这是通过 Portal 完成的方式:
这就是通过 C# 完成的方式 API:
private static VirtualMachineConfiguration ConfigureVM()
{
var imageNames = new List<string> { "microsoft/dotnet-framework:4.7" };
var containerConfig = new ContainerConfiguration
{
ContainerImageNames = imageNames
};
var offer = "WindowsServer";
var publisher = "MicrosoftWindowsServer";
var imageSku = "2016-Datacenter-with-Containers";
var imageReference = new ImageReference(offer, publisher, imageSku);
var nodeSku = "batch.node.windows amd64";
var vmConfig = new VirtualMachineConfiguration(imageReference, nodeSku)
{
ContainerConfiguration = containerConfig
};
return vmConfig;
}
现在我们正在自动化部署,所以我想通过 ARM 模板做同样的事情(这是 Azure Batch 帐户的子资源,所以名称和类型都可以) :
"resources": [
{
"name": "Test",
"type": "pools",
"apiVersion": "2017-09-01",
"properties": {
"vmSize": "STANDARD_A1",
"deploymentConfiguration": {
"virtualMachineConfiguration": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter-with-Containers"
},
"nodeAgentSkuId": "batch.node.windows amd64",
"containerConfiguration": {
"imageNames": [ "microsoft/dotnet-framework:4.7" ]
}
}
}
}
}
]
这是行不通的。部署时,我得到:
Could not find member 'containerConfiguration' on object of type 'VirtualMachineConfiguration'.
Path 'properties.deploymentConfiguration.virtualMachineConfiguration.containerConfiguration'
没有 containerConfiguration
部分工作正常 - 我得到的虚拟机有 docker,只是没有图像。我明白为什么会这样 - 模板 does not have this property as opposed to .NET class.
所以...有什么解决方法吗?我想这不是第一次模板与功能不同步。
在最近的更新中,Batch 的 ARM 提供程序得到改进,允许创建启用容器的池。以下 ARM 模板将创建一个容器池,请注意 API 版本已更新。
{
"type": "Microsoft.Batch/batchAccounts/pools",
"name": "[concat(variables('batchAccountName'), '/', parameters('poolID'))]",
"apiVersion": "2018-12-01",
"scale": null,
"properties": {
"vmSize": "[parameters('virtualMachineSize')]",
"networkConfiguration": {
"subnetId": "[parameters('virtualNetworkSubnetId')]"
},
"maxTasksPerNode": 1,
"taskSchedulingPolicy": {
"nodeFillType": "Spread"
},
"deploymentConfiguration": {
"virtualMachineConfiguration": {
"containerConfiguration": {
"containerImageNames": "[parameters('dockerImagesToCache')]",
"type": "DockerCompatible"
},
"imageReference": {
"publisher": "microsoft-azure-batch",
"offer": "ubuntu-server-container",
"sku": "16-04-lts",
"version": "latest"
},
"nodeAgentSkuId": "batch.node.ubuntu 16.04"
}
},
"scaleSettings": {
"autoScale": {
"evaluationInterval": "PT5M",
"formula": "[concat('startingNumberOfVMs = 0;maxNumberofVMs = ', parameters('maxNodeCount'), ';pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(160 * TimeInterval_Second);pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(160 * TimeInterval_Second));$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);')]"
}
}
},
"dependsOn": [
"[resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName'))]"
]
}
----- 现在不需要以前的答案了 -----
我设法找到了使用 ACI 容器以及托管服务标识和一些 Python 的解决方法。它不漂亮,但确实有效。
模板流程如下:
- 已创建 MSI
- 为 MSI 分配了资源组的贡献者权限
- Batch 帐户已创建
- ACI 实例是 运行,它提取模板化的
pool.json
文件并使用 python 脚本填写所需的参数。 python 使用 MSI 身份登录到 az cli
,然后继续创建池。
这是完整的设置,您可能需要对其进行调整以适合您的场景。
python脚本和pool.json
文件需要上传到public位置,例如blob存储或git,然后_artifactLocation
参数用于告诉模板在哪里下载文件。
主模板:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": ""
}
},
"_artifactsLocationSasToken": {
"type": "string",
"metadata": {
"description": ""
}
},
"mountArgs": {
"type": "string",
"metadata": {
"description": "Arguments passed to the mount.py script."
}
},
"virtualNetworkSubnetId": {
"type": "string",
"metadata": {
"description": "The subnet in which Batch will be deployed. Requires the following ports to be enabled via NSG: https://docs.microsoft.com/en-us/azure/batch/batch-virtual-network#network-security-groups-1."
}
},
"maxTasksPerNode": {
"type": "int",
"defaultValue": 1
},
"maxNodeCount": {
"type": "int",
"defaultValue": 3
},
"virtualMachineSize": {
"type": "string",
"defaultValue": "Standard_F8s_v2",
"metadata": {
"description": "Size of VMs in the VM Scale Set."
}
},
"storageAccountSku": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"poolId": {
"type": "string",
"defaultValue": "defaultpool"
}
},
"variables": {
"identityName": "batchpoolcreator",
"storageAccountName": "[concat('batch', uniqueString(resourceGroup().id))]",
"batchAccountName": "[concat('batch', uniqueString(resourceGroup().id))]",
"batchEndpoint": "[concat('https://', variables('batchAccountName'), '.' , parameters('location'), '.batch.azure.com')]",
"_comment": "The role assignment ID is required to be a guid, we use this to generate a repeatable guid",
"roleAssignmentIdRg": "[guid(concat(resourceGroup().id, 'contributorRG'))]",
"_comment": "This is the ID used to set the contributor permission on a role.",
"contributorRoleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]"
},
"resources": [
{
"comments": "Create an identity to use for creating the Azure Batch pool with container support (will be assigned to ACI instance)",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[variables('identityName')]",
"apiVersion": "2015-08-31-preview",
"location": "[resourceGroup().location]"
},
{
"comments": "Assign the idenity contributor rights to the resource group",
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2017-05-01",
"name": "[variables('roleAssignmentIdRg')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
"principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2015-08-31-preview').principalId]",
"scope": "[resourceGroup().id]"
}
},
{
"comments": "This is the storage account used by Azure Batch for file processing/storage",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountname')]",
"apiVersion": "2016-01-01",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountsku')]"
},
"kind": "Storage",
"tags": {
"ObjectName": "[variables('storageAccountName')]"
},
"properties": {}
},
{
"type": "Microsoft.Batch/batchAccounts",
"name": "[variables('batchAccountName')]",
"apiVersion": "2015-12-01",
"location": "[parameters('location')]",
"tags": {
"ObjectName": "[variables('batchAccountName')]"
},
"properties": {
"autoStorage": {
"storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-10-01",
"name": "[substring(concat('batchpool', uniqueString(resourceGroup().id)), 0, 20)]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]",
"[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentIdRg'))]",
"[resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName'))]"
],
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]": {}
}
},
"properties": {
"osType": "Linux",
"restartPolicy": "Never",
"containers": [
{
"name": "azure-cli",
"properties": {
"image": "microsoft/azure-cli",
"command": [
"/bin/bash",
"-c",
"[concat('curl -fsSL ', parameters('_artifactsLocation'), '/azurebatch/configurepool.py', parameters('_artifactsLocationSasToken'), ' > configurepool.py && python3 ./configurepool.py \"', parameters('poolId'), '\" ', parameters('virtualMachineSize'), ' \"', parameters('mountArgs'), '\" ', parameters('_artifactsLocation'), ' ', parameters('_artifactsLocationSasToken'), ' ', parameters('virtualNetworkSubnetId'), ' ', parameters('maxNodeCount'), ' ', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), ' ', resourceGroup().name, ' ', variables('batchAccountName'))]"
],
"resources": {
"requests": {
"cpu": 1,
"memoryInGB": 1
}
}
}
}
]
}
}
],
"outputs": {
"storageAccountName": {
"type": "string",
"value": "[variables('storageAccountName')]"
},
"batchAccountName": {
"type": "string",
"value": "[variables('batchAccountName')]"
},
"batchEndpoint": {
"type": "string",
"value": "[variables('batchEndpoint')]"
},
"batchAccountKey": {
"type": "securestring",
"value": "[listKeys(resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName')), '2017-09-01').primary]"
},
"batchPoolId": {
"type": "string",
"value": "[parameters('poolId')]"
}
}
}
Pool.json
{
"id": "POOL_ID_HERE",
"vmSize": "VM_SIZE_HERE",
"enableAutoScale": true,
"autoScaleFormula": "startingNumberOfVMs = 0;maxNumberofVMs = MAX_NODE_COUNT_HERE;pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(160 * TimeInterval_Second);pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(160 * TimeInterval_Second));$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);",
"autoScaleEvaluationInterval": "PT5M",
"enableInterNodeCommunication": false,
"startTask": {
"commandLine": "/usr/bin/python3 mount.py MOUNT_ARGS_HERE",
"resourceFiles": [
{
"blobSource": "ARTIFACT_LOCATION_HERE/examplemountscript/script.pyARTIFACT_SAS_HERE",
"filePath": "./mount.py",
"fileMode": "777"
}
],
"userIdentity": {
"autoUser": {
"scope": "pool",
"elevationLevel": "admin"
}
},
"maxTaskRetryCount": 0,
"waitForSuccess": true
},
"maxTasksPerNode": 1,
"taskSchedulingPolicy": {
"nodeFillType": "Spread"
},
"virtualMachineConfiguration": {
"containerConfiguration": {
"containerImageNames": [
"ubuntu",
"python"
]
},
"imageReference": {
"publisher": "microsoft-azure-batch",
"offer": "ubuntu-server-container",
"sku": "16-04-lts",
"version": "1.0.6"
},
"nodeAgentSKUId": "batch.node.ubuntu 16.04"
},
"networkConfiguration": {
"subnetId": "SUBNET_ID_HERE"
}
}
configurepool.py:
import subprocess
import sys
import urllib.request
def run_az_command(cmdArray):
try:
print("Attempt run {}".format(cmdArray))
subprocess.check_call(cmdArray)
print("Install completed successfully")
except subprocess.CalledProcessError as e:
print("Failed running: {} error: {}".format(cmdArray, e))
exit(4)
if len(sys.argv) != 11:
print(
"Expected 'poolid', 'vm_size', 'mount_args', 'artifact_location', 'artifact_sas', 'subnet_id', 'max_node_count', 'msi_name', 'resource_group_name' , 'batch_account_name'"
)
exit(1)
pool_id = str(sys.argv[1])
vm_size = str(sys.argv[2])
mount_args = str(sys.argv[3])
artifact_location = str(sys.argv[4])
artifact_sas = str(sys.argv[5])
subnet_id = str(sys.argv[6])
max_node_count = str(sys.argv[7])
msi_name = str(sys.argv[8])
resource_group_name = str(sys.argv[9])
batch_account_name = str(sys.argv[10])
url = "{0}/azurebatch/pool.json{1}".format(artifact_location, artifact_sas)
response = urllib.request.urlopen(url)
data = response.read()
text = data.decode("utf-8")
# Replace the target string
text = text.replace("POOL_ID_HERE", pool_id)
text = text.replace("VM_SIZE_HERE", vm_size)
text = text.replace("MOUNT_ARGS_HERE", mount_args)
text = text.replace("ARTIFACT_LOCATION_HERE", artifact_location)
text = text.replace("ARTIFACT_SAS_HERE", artifact_sas)
text = text.replace("SUBNET_ID_HERE", subnet_id)
text = text.replace("MAX_NODE_COUNT_HERE", max_node_count)
# Write the file out again
with open("pool.complete.json", "w") as file:
file.write(text)
run_az_command(["az", "login", "--identity", "-u", msi_name])
run_az_command(["az", "batch", "account", "login", "--name", batch_account_name, "-g", resource_group_name])
run_az_command(["az", "batch", "pool", "create", "--json-file", "pool.complete.json"])
我们正在使用 Azure Batch,我们需要在虚拟机上使用 Windows Docker 个容器。
这是通过 Portal 完成的方式:
这就是通过 C# 完成的方式 API:
private static VirtualMachineConfiguration ConfigureVM()
{
var imageNames = new List<string> { "microsoft/dotnet-framework:4.7" };
var containerConfig = new ContainerConfiguration
{
ContainerImageNames = imageNames
};
var offer = "WindowsServer";
var publisher = "MicrosoftWindowsServer";
var imageSku = "2016-Datacenter-with-Containers";
var imageReference = new ImageReference(offer, publisher, imageSku);
var nodeSku = "batch.node.windows amd64";
var vmConfig = new VirtualMachineConfiguration(imageReference, nodeSku)
{
ContainerConfiguration = containerConfig
};
return vmConfig;
}
现在我们正在自动化部署,所以我想通过 ARM 模板做同样的事情(这是 Azure Batch 帐户的子资源,所以名称和类型都可以) :
"resources": [
{
"name": "Test",
"type": "pools",
"apiVersion": "2017-09-01",
"properties": {
"vmSize": "STANDARD_A1",
"deploymentConfiguration": {
"virtualMachineConfiguration": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter-with-Containers"
},
"nodeAgentSkuId": "batch.node.windows amd64",
"containerConfiguration": {
"imageNames": [ "microsoft/dotnet-framework:4.7" ]
}
}
}
}
}
]
这是行不通的。部署时,我得到:
Could not find member 'containerConfiguration' on object of type 'VirtualMachineConfiguration'.
Path 'properties.deploymentConfiguration.virtualMachineConfiguration.containerConfiguration'
没有 containerConfiguration
部分工作正常 - 我得到的虚拟机有 docker,只是没有图像。我明白为什么会这样 - 模板 does not have this property as opposed to .NET class.
所以...有什么解决方法吗?我想这不是第一次模板与功能不同步。
在最近的更新中,Batch 的 ARM 提供程序得到改进,允许创建启用容器的池。以下 ARM 模板将创建一个容器池,请注意 API 版本已更新。
{
"type": "Microsoft.Batch/batchAccounts/pools",
"name": "[concat(variables('batchAccountName'), '/', parameters('poolID'))]",
"apiVersion": "2018-12-01",
"scale": null,
"properties": {
"vmSize": "[parameters('virtualMachineSize')]",
"networkConfiguration": {
"subnetId": "[parameters('virtualNetworkSubnetId')]"
},
"maxTasksPerNode": 1,
"taskSchedulingPolicy": {
"nodeFillType": "Spread"
},
"deploymentConfiguration": {
"virtualMachineConfiguration": {
"containerConfiguration": {
"containerImageNames": "[parameters('dockerImagesToCache')]",
"type": "DockerCompatible"
},
"imageReference": {
"publisher": "microsoft-azure-batch",
"offer": "ubuntu-server-container",
"sku": "16-04-lts",
"version": "latest"
},
"nodeAgentSkuId": "batch.node.ubuntu 16.04"
}
},
"scaleSettings": {
"autoScale": {
"evaluationInterval": "PT5M",
"formula": "[concat('startingNumberOfVMs = 0;maxNumberofVMs = ', parameters('maxNodeCount'), ';pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(160 * TimeInterval_Second);pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(160 * TimeInterval_Second));$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);')]"
}
}
},
"dependsOn": [
"[resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName'))]"
]
}
----- 现在不需要以前的答案了 -----
我设法找到了使用 ACI 容器以及托管服务标识和一些 Python 的解决方法。它不漂亮,但确实有效。
模板流程如下:
- 已创建 MSI
- 为 MSI 分配了资源组的贡献者权限
- Batch 帐户已创建
- ACI 实例是 运行,它提取模板化的
pool.json
文件并使用 python 脚本填写所需的参数。 python 使用 MSI 身份登录到az cli
,然后继续创建池。
这是完整的设置,您可能需要对其进行调整以适合您的场景。
python脚本和pool.json
文件需要上传到public位置,例如blob存储或git,然后_artifactLocation
参数用于告诉模板在哪里下载文件。
主模板:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"_artifactsLocation": {
"type": "string",
"metadata": {
"description": ""
}
},
"_artifactsLocationSasToken": {
"type": "string",
"metadata": {
"description": ""
}
},
"mountArgs": {
"type": "string",
"metadata": {
"description": "Arguments passed to the mount.py script."
}
},
"virtualNetworkSubnetId": {
"type": "string",
"metadata": {
"description": "The subnet in which Batch will be deployed. Requires the following ports to be enabled via NSG: https://docs.microsoft.com/en-us/azure/batch/batch-virtual-network#network-security-groups-1."
}
},
"maxTasksPerNode": {
"type": "int",
"defaultValue": 1
},
"maxNodeCount": {
"type": "int",
"defaultValue": 3
},
"virtualMachineSize": {
"type": "string",
"defaultValue": "Standard_F8s_v2",
"metadata": {
"description": "Size of VMs in the VM Scale Set."
}
},
"storageAccountSku": {
"type": "string",
"defaultValue": "Standard_LRS",
"allowedValues": [
"Standard_LRS",
"Standard_GRS",
"Standard_ZRS",
"Premium_LRS"
],
"metadata": {
"description": "Storage Account type"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
},
"poolId": {
"type": "string",
"defaultValue": "defaultpool"
}
},
"variables": {
"identityName": "batchpoolcreator",
"storageAccountName": "[concat('batch', uniqueString(resourceGroup().id))]",
"batchAccountName": "[concat('batch', uniqueString(resourceGroup().id))]",
"batchEndpoint": "[concat('https://', variables('batchAccountName'), '.' , parameters('location'), '.batch.azure.com')]",
"_comment": "The role assignment ID is required to be a guid, we use this to generate a repeatable guid",
"roleAssignmentIdRg": "[guid(concat(resourceGroup().id, 'contributorRG'))]",
"_comment": "This is the ID used to set the contributor permission on a role.",
"contributorRoleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]"
},
"resources": [
{
"comments": "Create an identity to use for creating the Azure Batch pool with container support (will be assigned to ACI instance)",
"type": "Microsoft.ManagedIdentity/userAssignedIdentities",
"name": "[variables('identityName')]",
"apiVersion": "2015-08-31-preview",
"location": "[resourceGroup().location]"
},
{
"comments": "Assign the idenity contributor rights to the resource group",
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2017-05-01",
"name": "[variables('roleAssignmentIdRg')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]"
],
"properties": {
"roleDefinitionId": "[variables('contributorRoleDefinitionId')]",
"principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), '2015-08-31-preview').principalId]",
"scope": "[resourceGroup().id]"
}
},
{
"comments": "This is the storage account used by Azure Batch for file processing/storage",
"type": "Microsoft.Storage/storageAccounts",
"name": "[variables('storageAccountname')]",
"apiVersion": "2016-01-01",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('storageAccountsku')]"
},
"kind": "Storage",
"tags": {
"ObjectName": "[variables('storageAccountName')]"
},
"properties": {}
},
{
"type": "Microsoft.Batch/batchAccounts",
"name": "[variables('batchAccountName')]",
"apiVersion": "2015-12-01",
"location": "[parameters('location')]",
"tags": {
"ObjectName": "[variables('batchAccountName')]"
},
"properties": {
"autoStorage": {
"storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
}
},
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.ContainerInstance/containerGroups",
"apiVersion": "2018-10-01",
"name": "[substring(concat('batchpool', uniqueString(resourceGroup().id)), 0, 20)]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]",
"[resourceId('Microsoft.Authorization/roleAssignments', variables('roleAssignmentIdRg'))]",
"[resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName'))]"
],
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]": {}
}
},
"properties": {
"osType": "Linux",
"restartPolicy": "Never",
"containers": [
{
"name": "azure-cli",
"properties": {
"image": "microsoft/azure-cli",
"command": [
"/bin/bash",
"-c",
"[concat('curl -fsSL ', parameters('_artifactsLocation'), '/azurebatch/configurepool.py', parameters('_artifactsLocationSasToken'), ' > configurepool.py && python3 ./configurepool.py \"', parameters('poolId'), '\" ', parameters('virtualMachineSize'), ' \"', parameters('mountArgs'), '\" ', parameters('_artifactsLocation'), ' ', parameters('_artifactsLocationSasToken'), ' ', parameters('virtualNetworkSubnetId'), ' ', parameters('maxNodeCount'), ' ', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName')), ' ', resourceGroup().name, ' ', variables('batchAccountName'))]"
],
"resources": {
"requests": {
"cpu": 1,
"memoryInGB": 1
}
}
}
}
]
}
}
],
"outputs": {
"storageAccountName": {
"type": "string",
"value": "[variables('storageAccountName')]"
},
"batchAccountName": {
"type": "string",
"value": "[variables('batchAccountName')]"
},
"batchEndpoint": {
"type": "string",
"value": "[variables('batchEndpoint')]"
},
"batchAccountKey": {
"type": "securestring",
"value": "[listKeys(resourceId('Microsoft.Batch/batchAccounts', variables('batchAccountName')), '2017-09-01').primary]"
},
"batchPoolId": {
"type": "string",
"value": "[parameters('poolId')]"
}
}
}
Pool.json
{
"id": "POOL_ID_HERE",
"vmSize": "VM_SIZE_HERE",
"enableAutoScale": true,
"autoScaleFormula": "startingNumberOfVMs = 0;maxNumberofVMs = MAX_NODE_COUNT_HERE;pendingTaskSamplePercent = $PendingTasks.GetSamplePercent(160 * TimeInterval_Second);pendingTaskSamples = pendingTaskSamplePercent < 70 ? startingNumberOfVMs : avg($PendingTasks.GetSample(160 * TimeInterval_Second));$TargetDedicatedNodes=min(maxNumberofVMs, pendingTaskSamples);",
"autoScaleEvaluationInterval": "PT5M",
"enableInterNodeCommunication": false,
"startTask": {
"commandLine": "/usr/bin/python3 mount.py MOUNT_ARGS_HERE",
"resourceFiles": [
{
"blobSource": "ARTIFACT_LOCATION_HERE/examplemountscript/script.pyARTIFACT_SAS_HERE",
"filePath": "./mount.py",
"fileMode": "777"
}
],
"userIdentity": {
"autoUser": {
"scope": "pool",
"elevationLevel": "admin"
}
},
"maxTaskRetryCount": 0,
"waitForSuccess": true
},
"maxTasksPerNode": 1,
"taskSchedulingPolicy": {
"nodeFillType": "Spread"
},
"virtualMachineConfiguration": {
"containerConfiguration": {
"containerImageNames": [
"ubuntu",
"python"
]
},
"imageReference": {
"publisher": "microsoft-azure-batch",
"offer": "ubuntu-server-container",
"sku": "16-04-lts",
"version": "1.0.6"
},
"nodeAgentSKUId": "batch.node.ubuntu 16.04"
},
"networkConfiguration": {
"subnetId": "SUBNET_ID_HERE"
}
}
configurepool.py:
import subprocess
import sys
import urllib.request
def run_az_command(cmdArray):
try:
print("Attempt run {}".format(cmdArray))
subprocess.check_call(cmdArray)
print("Install completed successfully")
except subprocess.CalledProcessError as e:
print("Failed running: {} error: {}".format(cmdArray, e))
exit(4)
if len(sys.argv) != 11:
print(
"Expected 'poolid', 'vm_size', 'mount_args', 'artifact_location', 'artifact_sas', 'subnet_id', 'max_node_count', 'msi_name', 'resource_group_name' , 'batch_account_name'"
)
exit(1)
pool_id = str(sys.argv[1])
vm_size = str(sys.argv[2])
mount_args = str(sys.argv[3])
artifact_location = str(sys.argv[4])
artifact_sas = str(sys.argv[5])
subnet_id = str(sys.argv[6])
max_node_count = str(sys.argv[7])
msi_name = str(sys.argv[8])
resource_group_name = str(sys.argv[9])
batch_account_name = str(sys.argv[10])
url = "{0}/azurebatch/pool.json{1}".format(artifact_location, artifact_sas)
response = urllib.request.urlopen(url)
data = response.read()
text = data.decode("utf-8")
# Replace the target string
text = text.replace("POOL_ID_HERE", pool_id)
text = text.replace("VM_SIZE_HERE", vm_size)
text = text.replace("MOUNT_ARGS_HERE", mount_args)
text = text.replace("ARTIFACT_LOCATION_HERE", artifact_location)
text = text.replace("ARTIFACT_SAS_HERE", artifact_sas)
text = text.replace("SUBNET_ID_HERE", subnet_id)
text = text.replace("MAX_NODE_COUNT_HERE", max_node_count)
# Write the file out again
with open("pool.complete.json", "w") as file:
file.write(text)
run_az_command(["az", "login", "--identity", "-u", msi_name])
run_az_command(["az", "batch", "account", "login", "--name", batch_account_name, "-g", resource_group_name])
run_az_command(["az", "batch", "pool", "create", "--json-file", "pool.complete.json"])