Deploy Azure Batch Pools

The azure-native:batch:Pool resource, part of the Pulumi Azure Native provider, defines a Batch pool: its compute nodes, scaling behavior, and runtime configuration. This guide focuses on four capabilities: marketplace and custom image deployment, autoscaling and fixed-scale configuration, storage and network endpoints, and VM extensions and OS upgrade policies.

Pools belong to a Batch account and may reference Compute Gallery images, VNet subnets, or other Azure resources. The examples are intentionally small. Combine them with your own Batch account, networking, and application deployment logic.

Create a pool with marketplace image and autoscaling

Most Batch workloads start with a pool that uses a marketplace image and scales automatically based on demand.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            imageReference: {
                offer: "UbuntuServer",
                publisher: "Canonical",
                sku: "18.04-LTS",
                version: "latest",
            },
            nodeAgentSkuId: "batch.node.ubuntu 18.04",
        },
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    scaleSettings: {
        autoScale: {
            evaluationInterval: "PT5M",
            formula: "$TargetDedicatedNodes=1",
        },
    },
    vmSize: "STANDARD_D4",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "image_reference": {
                "offer": "UbuntuServer",
                "publisher": "Canonical",
                "sku": "18.04-LTS",
                "version": "latest",
            },
            "node_agent_sku_id": "batch.node.ubuntu 18.04",
        },
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    scale_settings={
        "auto_scale": {
            "evaluation_interval": "PT5M",
            "formula": "$TargetDedicatedNodes=1",
        },
    },
    vm_size="STANDARD_D4")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					ImageReference: &batch.ImageReferenceArgs{
						Offer:     pulumi.String("UbuntuServer"),
						Publisher: pulumi.String("Canonical"),
						Sku:       pulumi.String("18.04-LTS"),
						Version:   pulumi.String("latest"),
					},
					NodeAgentSkuId: pulumi.String("batch.node.ubuntu 18.04"),
				},
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			ScaleSettings: &batch.ScaleSettingsArgs{
				AutoScale: &batch.AutoScaleSettingsArgs{
					EvaluationInterval: pulumi.String("PT5M"),
					Formula:            pulumi.String("$TargetDedicatedNodes=1"),
				},
			},
			VmSize: pulumi.String("STANDARD_D4"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Offer = "UbuntuServer",
                    Publisher = "Canonical",
                    Sku = "18.04-LTS",
                    Version = "latest",
                },
                NodeAgentSkuId = "batch.node.ubuntu 18.04",
            },
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        ScaleSettings = new AzureNative.Batch.Inputs.ScaleSettingsArgs
        {
            AutoScale = new AzureNative.Batch.Inputs.AutoScaleSettingsArgs
            {
                EvaluationInterval = "PT5M",
                Formula = "$TargetDedicatedNodes=1",
            },
        },
        VmSize = "STANDARD_D4",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import com.pulumi.azurenative.batch.inputs.ScaleSettingsArgs;
import com.pulumi.azurenative.batch.inputs.AutoScaleSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .imageReference(ImageReferenceArgs.builder()
                        .offer("UbuntuServer")
                        .publisher("Canonical")
                        .sku("18.04-LTS")
                        .version("latest")
                        .build())
                    .nodeAgentSkuId("batch.node.ubuntu 18.04")
                    .build())
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .scaleSettings(ScaleSettingsArgs.builder()
                .autoScale(AutoScaleSettingsArgs.builder()
                    .evaluationInterval("PT5M")
                    .formula("$TargetDedicatedNodes=1")
                    .build())
                .build())
            .vmSize("STANDARD_D4")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          imageReference:
            offer: UbuntuServer
            publisher: Canonical
            sku: 18.04-LTS
            version: latest
          nodeAgentSkuId: batch.node.ubuntu 18.04
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      scaleSettings:
        autoScale:
          evaluationInterval: PT5M
          formula: $TargetDedicatedNodes=1
      vmSize: STANDARD_D4

The imageReference selects a marketplace image by publisher, offer, and SKU. The nodeAgentSkuId tells Batch which agent software to install. The scaleSettings block defines autoscaling: the formula property contains a Batch autoscale expression that evaluates periodically (every evaluationInterval) to determine target node counts.

Teams with specialized software or configurations often build custom images in Azure Compute Gallery and deploy pools from those images.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            imageReference: {
                id: "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
            },
            nodeAgentSkuId: "batch.node.ubuntu 18.04",
        },
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    vmSize: "STANDARD_D4",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "image_reference": {
                "id": "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
            },
            "node_agent_sku_id": "batch.node.ubuntu 18.04",
        },
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    vm_size="STANDARD_D4")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					ImageReference: &batch.ImageReferenceArgs{
						Id: pulumi.String("/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1"),
					},
					NodeAgentSkuId: pulumi.String("batch.node.ubuntu 18.04"),
				},
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			VmSize:            pulumi.String("STANDARD_D4"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Id = "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
                },
                NodeAgentSkuId = "batch.node.ubuntu 18.04",
            },
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        VmSize = "STANDARD_D4",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .imageReference(ImageReferenceArgs.builder()
                        .id("/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1")
                        .build())
                    .nodeAgentSkuId("batch.node.ubuntu 18.04")
                    .build())
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .vmSize("STANDARD_D4")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          imageReference:
            id: /subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1
          nodeAgentSkuId: batch.node.ubuntu 18.04
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      vmSize: STANDARD_D4

When imageReference uses an id property instead of publisher/offer/sku, Batch deploys nodes from the specified Compute Gallery image. The nodeAgentSkuId must match the OS family of the custom image. This approach lets you pre-install dependencies and avoid startup scripts.

Configure storage, encryption, and network endpoints

Production workloads often require data disks for scratch space, disk encryption for compliance, and inbound NAT pools for remote access.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            dataDisks: [
                {
                    caching: azure_native.batch.CachingType.ReadWrite,
                    diskSizeGB: 30,
                    lun: 0,
                    storageAccountType: azure_native.batch.StorageAccountType.Premium_LRS,
                },
                {
                    caching: azure_native.batch.CachingType.None,
                    diskSizeGB: 200,
                    lun: 1,
                    storageAccountType: azure_native.batch.StorageAccountType.Standard_LRS,
                },
            ],
            diskEncryptionConfiguration: {
                targets: [
                    azure_native.batch.DiskEncryptionTarget.OsDisk,
                    azure_native.batch.DiskEncryptionTarget.TemporaryDisk,
                ],
            },
            imageReference: {
                offer: "WindowsServer",
                publisher: "MicrosoftWindowsServer",
                sku: "2016-Datacenter-SmallDisk",
                version: "latest",
            },
            licenseType: "Windows_Server",
            nodeAgentSkuId: "batch.node.windows amd64",
            nodePlacementConfiguration: {
                policy: azure_native.batch.NodePlacementPolicyType.Zonal,
            },
            osDisk: {
                ephemeralOSDiskSettings: {
                    placement: azure_native.batch.DiffDiskPlacement.CacheDisk,
                },
            },
            windowsConfiguration: {
                enableAutomaticUpdates: false,
            },
        },
    },
    networkConfiguration: {
        endpointConfiguration: {
            inboundNatPools: [{
                backendPort: 12001,
                frontendPortRangeEnd: 15100,
                frontendPortRangeStart: 15000,
                name: "testnat",
                networkSecurityGroupRules: [
                    {
                        access: azure_native.batch.NetworkSecurityGroupRuleAccess.Allow,
                        priority: 150,
                        sourceAddressPrefix: "192.100.12.45",
                        sourcePortRanges: [
                            "1",
                            "2",
                        ],
                    },
                    {
                        access: azure_native.batch.NetworkSecurityGroupRuleAccess.Deny,
                        priority: 3500,
                        sourceAddressPrefix: "*",
                        sourcePortRanges: ["*"],
                    },
                ],
                protocol: azure_native.batch.InboundEndpointProtocol.TCP,
            }],
        },
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    scaleSettings: {
        autoScale: {
            evaluationInterval: "PT5M",
            formula: "$TargetDedicatedNodes=1",
        },
    },
    vmSize: "STANDARD_D4",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "data_disks": [
                {
                    "caching": azure_native.batch.CachingType.READ_WRITE,
                    "disk_size_gb": 30,
                    "lun": 0,
                    "storage_account_type": azure_native.batch.StorageAccountType.PREMIUM_LRS,
                },
                {
                    "caching": azure_native.batch.CachingType.NONE,
                    "disk_size_gb": 200,
                    "lun": 1,
                    "storage_account_type": azure_native.batch.StorageAccountType.STANDARD_LRS,
                },
            ],
            "disk_encryption_configuration": {
                "targets": [
                    azure_native.batch.DiskEncryptionTarget.OS_DISK,
                    azure_native.batch.DiskEncryptionTarget.TEMPORARY_DISK,
                ],
            },
            "image_reference": {
                "offer": "WindowsServer",
                "publisher": "MicrosoftWindowsServer",
                "sku": "2016-Datacenter-SmallDisk",
                "version": "latest",
            },
            "license_type": "Windows_Server",
            "node_agent_sku_id": "batch.node.windows amd64",
            "node_placement_configuration": {
                "policy": azure_native.batch.NodePlacementPolicyType.ZONAL,
            },
            "os_disk": {
                "ephemeral_os_disk_settings": {
                    "placement": azure_native.batch.DiffDiskPlacement.CACHE_DISK,
                },
            },
            "windows_configuration": {
                "enable_automatic_updates": False,
            },
        },
    },
    network_configuration={
        "endpoint_configuration": {
            "inbound_nat_pools": [{
                "backend_port": 12001,
                "frontend_port_range_end": 15100,
                "frontend_port_range_start": 15000,
                "name": "testnat",
                "network_security_group_rules": [
                    {
                        "access": azure_native.batch.NetworkSecurityGroupRuleAccess.ALLOW,
                        "priority": 150,
                        "source_address_prefix": "192.100.12.45",
                        "source_port_ranges": [
                            "1",
                            "2",
                        ],
                    },
                    {
                        "access": azure_native.batch.NetworkSecurityGroupRuleAccess.DENY,
                        "priority": 3500,
                        "source_address_prefix": "*",
                        "source_port_ranges": ["*"],
                    },
                ],
                "protocol": azure_native.batch.InboundEndpointProtocol.TCP,
            }],
        },
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    scale_settings={
        "auto_scale": {
            "evaluation_interval": "PT5M",
            "formula": "$TargetDedicatedNodes=1",
        },
    },
    vm_size="STANDARD_D4")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					DataDisks: batch.DataDiskArray{
						&batch.DataDiskArgs{
							Caching:            batch.CachingTypeReadWrite,
							DiskSizeGB:         pulumi.Int(30),
							Lun:                pulumi.Int(0),
							StorageAccountType: batch.StorageAccountType_Premium_LRS,
						},
						&batch.DataDiskArgs{
							Caching:            batch.CachingTypeNone,
							DiskSizeGB:         pulumi.Int(200),
							Lun:                pulumi.Int(1),
							StorageAccountType: batch.StorageAccountType_Standard_LRS,
						},
					},
					DiskEncryptionConfiguration: &batch.DiskEncryptionConfigurationArgs{
						Targets: batch.DiskEncryptionTargetArray{
							batch.DiskEncryptionTargetOsDisk,
							batch.DiskEncryptionTargetTemporaryDisk,
						},
					},
					ImageReference: &batch.ImageReferenceArgs{
						Offer:     pulumi.String("WindowsServer"),
						Publisher: pulumi.String("MicrosoftWindowsServer"),
						Sku:       pulumi.String("2016-Datacenter-SmallDisk"),
						Version:   pulumi.String("latest"),
					},
					LicenseType:    pulumi.String("Windows_Server"),
					NodeAgentSkuId: pulumi.String("batch.node.windows amd64"),
					NodePlacementConfiguration: &batch.NodePlacementConfigurationArgs{
						Policy: batch.NodePlacementPolicyTypeZonal,
					},
					OsDisk: &batch.OSDiskArgs{
						EphemeralOSDiskSettings: &batch.DiffDiskSettingsArgs{
							Placement: batch.DiffDiskPlacementCacheDisk,
						},
					},
					WindowsConfiguration: &batch.WindowsConfigurationArgs{
						EnableAutomaticUpdates: pulumi.Bool(false),
					},
				},
			},
			NetworkConfiguration: &batch.NetworkConfigurationArgs{
				EndpointConfiguration: &batch.PoolEndpointConfigurationArgs{
					InboundNatPools: batch.InboundNatPoolArray{
						&batch.InboundNatPoolArgs{
							BackendPort:            pulumi.Int(12001),
							FrontendPortRangeEnd:   pulumi.Int(15100),
							FrontendPortRangeStart: pulumi.Int(15000),
							Name:                   pulumi.String("testnat"),
							NetworkSecurityGroupRules: batch.NetworkSecurityGroupRuleArray{
								&batch.NetworkSecurityGroupRuleArgs{
									Access:              batch.NetworkSecurityGroupRuleAccessAllow,
									Priority:            pulumi.Int(150),
									SourceAddressPrefix: pulumi.String("192.100.12.45"),
									SourcePortRanges: pulumi.StringArray{
										pulumi.String("1"),
										pulumi.String("2"),
									},
								},
								&batch.NetworkSecurityGroupRuleArgs{
									Access:              batch.NetworkSecurityGroupRuleAccessDeny,
									Priority:            pulumi.Int(3500),
									SourceAddressPrefix: pulumi.String("*"),
									SourcePortRanges: pulumi.StringArray{
										pulumi.String("*"),
									},
								},
							},
							Protocol: batch.InboundEndpointProtocolTCP,
						},
					},
				},
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			ScaleSettings: &batch.ScaleSettingsArgs{
				AutoScale: &batch.AutoScaleSettingsArgs{
					EvaluationInterval: pulumi.String("PT5M"),
					Formula:            pulumi.String("$TargetDedicatedNodes=1"),
				},
			},
			VmSize: pulumi.String("STANDARD_D4"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                DataDisks = new[]
                {
                    new AzureNative.Batch.Inputs.DataDiskArgs
                    {
                        Caching = AzureNative.Batch.CachingType.ReadWrite,
                        DiskSizeGB = 30,
                        Lun = 0,
                        StorageAccountType = AzureNative.Batch.StorageAccountType.Premium_LRS,
                    },
                    new AzureNative.Batch.Inputs.DataDiskArgs
                    {
                        Caching = AzureNative.Batch.CachingType.None,
                        DiskSizeGB = 200,
                        Lun = 1,
                        StorageAccountType = AzureNative.Batch.StorageAccountType.Standard_LRS,
                    },
                },
                DiskEncryptionConfiguration = new AzureNative.Batch.Inputs.DiskEncryptionConfigurationArgs
                {
                    Targets = new[]
                    {
                        AzureNative.Batch.DiskEncryptionTarget.OsDisk,
                        AzureNative.Batch.DiskEncryptionTarget.TemporaryDisk,
                    },
                },
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Offer = "WindowsServer",
                    Publisher = "MicrosoftWindowsServer",
                    Sku = "2016-Datacenter-SmallDisk",
                    Version = "latest",
                },
                LicenseType = "Windows_Server",
                NodeAgentSkuId = "batch.node.windows amd64",
                NodePlacementConfiguration = new AzureNative.Batch.Inputs.NodePlacementConfigurationArgs
                {
                    Policy = AzureNative.Batch.NodePlacementPolicyType.Zonal,
                },
                OsDisk = new AzureNative.Batch.Inputs.OSDiskArgs
                {
                    EphemeralOSDiskSettings = new AzureNative.Batch.Inputs.DiffDiskSettingsArgs
                    {
                        Placement = AzureNative.Batch.DiffDiskPlacement.CacheDisk,
                    },
                },
                WindowsConfiguration = new AzureNative.Batch.Inputs.WindowsConfigurationArgs
                {
                    EnableAutomaticUpdates = false,
                },
            },
        },
        NetworkConfiguration = new AzureNative.Batch.Inputs.NetworkConfigurationArgs
        {
            EndpointConfiguration = new AzureNative.Batch.Inputs.PoolEndpointConfigurationArgs
            {
                InboundNatPools = new[]
                {
                    new AzureNative.Batch.Inputs.InboundNatPoolArgs
                    {
                        BackendPort = 12001,
                        FrontendPortRangeEnd = 15100,
                        FrontendPortRangeStart = 15000,
                        Name = "testnat",
                        NetworkSecurityGroupRules = new[]
                        {
                            new AzureNative.Batch.Inputs.NetworkSecurityGroupRuleArgs
                            {
                                Access = AzureNative.Batch.NetworkSecurityGroupRuleAccess.Allow,
                                Priority = 150,
                                SourceAddressPrefix = "192.100.12.45",
                                SourcePortRanges = new[]
                                {
                                    "1",
                                    "2",
                                },
                            },
                            new AzureNative.Batch.Inputs.NetworkSecurityGroupRuleArgs
                            {
                                Access = AzureNative.Batch.NetworkSecurityGroupRuleAccess.Deny,
                                Priority = 3500,
                                SourceAddressPrefix = "*",
                                SourcePortRanges = new[]
                                {
                                    "*",
                                },
                            },
                        },
                        Protocol = AzureNative.Batch.InboundEndpointProtocol.TCP,
                    },
                },
            },
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        ScaleSettings = new AzureNative.Batch.Inputs.ScaleSettingsArgs
        {
            AutoScale = new AzureNative.Batch.Inputs.AutoScaleSettingsArgs
            {
                EvaluationInterval = "PT5M",
                Formula = "$TargetDedicatedNodes=1",
            },
        },
        VmSize = "STANDARD_D4",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.DiskEncryptionConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import com.pulumi.azurenative.batch.inputs.NodePlacementConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.OSDiskArgs;
import com.pulumi.azurenative.batch.inputs.DiffDiskSettingsArgs;
import com.pulumi.azurenative.batch.inputs.WindowsConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.NetworkConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.PoolEndpointConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ScaleSettingsArgs;
import com.pulumi.azurenative.batch.inputs.AutoScaleSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .dataDisks(                    
                        DataDiskArgs.builder()
                            .caching("ReadWrite")
                            .diskSizeGB(30)
                            .lun(0)
                            .storageAccountType("Premium_LRS")
                            .build(),
                        DataDiskArgs.builder()
                            .caching("None")
                            .diskSizeGB(200)
                            .lun(1)
                            .storageAccountType("Standard_LRS")
                            .build())
                    .diskEncryptionConfiguration(DiskEncryptionConfigurationArgs.builder()
                        .targets(                        
                            "OsDisk",
                            "TemporaryDisk")
                        .build())
                    .imageReference(ImageReferenceArgs.builder()
                        .offer("WindowsServer")
                        .publisher("MicrosoftWindowsServer")
                        .sku("2016-Datacenter-SmallDisk")
                        .version("latest")
                        .build())
                    .licenseType("Windows_Server")
                    .nodeAgentSkuId("batch.node.windows amd64")
                    .nodePlacementConfiguration(NodePlacementConfigurationArgs.builder()
                        .policy("Zonal")
                        .build())
                    .osDisk(OSDiskArgs.builder()
                        .ephemeralOSDiskSettings(DiffDiskSettingsArgs.builder()
                            .placement("CacheDisk")
                            .build())
                        .build())
                    .windowsConfiguration(WindowsConfigurationArgs.builder()
                        .enableAutomaticUpdates(false)
                        .build())
                    .build())
                .build())
            .networkConfiguration(NetworkConfigurationArgs.builder()
                .endpointConfiguration(PoolEndpointConfigurationArgs.builder()
                    .inboundNatPools(InboundNatPoolArgs.builder()
                        .backendPort(12001)
                        .frontendPortRangeEnd(15100)
                        .frontendPortRangeStart(15000)
                        .name("testnat")
                        .networkSecurityGroupRules(                        
                            NetworkSecurityGroupRuleArgs.builder()
                                .access("Allow")
                                .priority(150)
                                .sourceAddressPrefix("192.100.12.45")
                                .sourcePortRanges(                                
                                    "1",
                                    "2")
                                .build(),
                            NetworkSecurityGroupRuleArgs.builder()
                                .access("Deny")
                                .priority(3500)
                                .sourceAddressPrefix("*")
                                .sourcePortRanges("*")
                                .build())
                        .protocol("TCP")
                        .build())
                    .build())
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .scaleSettings(ScaleSettingsArgs.builder()
                .autoScale(AutoScaleSettingsArgs.builder()
                    .evaluationInterval("PT5M")
                    .formula("$TargetDedicatedNodes=1")
                    .build())
                .build())
            .vmSize("STANDARD_D4")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          dataDisks:
            - caching: ReadWrite
              diskSizeGB: 30
              lun: 0
              storageAccountType: Premium_LRS
            - caching: None
              diskSizeGB: 200
              lun: 1
              storageAccountType: Standard_LRS
          diskEncryptionConfiguration:
            targets:
              - OsDisk
              - TemporaryDisk
          imageReference:
            offer: WindowsServer
            publisher: MicrosoftWindowsServer
            sku: 2016-Datacenter-SmallDisk
            version: latest
          licenseType: Windows_Server
          nodeAgentSkuId: batch.node.windows amd64
          nodePlacementConfiguration:
            policy: Zonal
          osDisk:
            ephemeralOSDiskSettings:
              placement: CacheDisk
          windowsConfiguration:
            enableAutomaticUpdates: false
      networkConfiguration:
        endpointConfiguration:
          inboundNatPools:
            - backendPort: 12001
              frontendPortRangeEnd: 15100
              frontendPortRangeStart: 15000
              name: testnat
              networkSecurityGroupRules:
                - access: Allow
                  priority: 150
                  sourceAddressPrefix: 192.100.12.45
                  sourcePortRanges:
                    - '1'
                    - '2'
                - access: Deny
                  priority: 3500
                  sourceAddressPrefix: '*'
                  sourcePortRanges:
                    - '*'
              protocol: TCP
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      scaleSettings:
        autoScale:
          evaluationInterval: PT5M
          formula: $TargetDedicatedNodes=1
      vmSize: STANDARD_D4

The dataDisks array attaches managed disks to each node at specified LUNs. The diskEncryptionConfiguration encrypts OS and temporary disks. The networkConfiguration block defines inbound NAT pools that map external port ranges to a backend port on each node, with networkSecurityGroupRules controlling access. This configuration gives you persistent storage, encryption at rest, and controlled remote access.

Install VM extensions for secrets and monitoring

Applications that need secrets from Key Vault or monitoring agents use VM extensions to configure nodes at startup.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            imageReference: {
                offer: "windowsserver",
                publisher: "microsoftwindowsserver",
                sku: "2022-datacenter-smalldisk",
            },
            nodeAgentSkuId: "batch.node.windows amd64",
            osDisk: {
                caching: azure_native.batch.CachingType.ReadWrite,
                diskSizeGB: 100,
                managedDisk: {
                    storageAccountType: azure_native.batch.StorageAccountType.StandardSSD_LRS,
                },
                writeAcceleratorEnabled: false,
            },
        },
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    scaleSettings: {
        fixedScale: {
            targetDedicatedNodes: 1,
            targetLowPriorityNodes: 0,
        },
    },
    vmSize: "Standard_d2s_v3",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "image_reference": {
                "offer": "windowsserver",
                "publisher": "microsoftwindowsserver",
                "sku": "2022-datacenter-smalldisk",
            },
            "node_agent_sku_id": "batch.node.windows amd64",
            "os_disk": {
                "caching": azure_native.batch.CachingType.READ_WRITE,
                "disk_size_gb": 100,
                "managed_disk": {
                    "storage_account_type": azure_native.batch.StorageAccountType.STANDARD_SS_D_LRS,
                },
                "write_accelerator_enabled": False,
            },
        },
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    scale_settings={
        "fixed_scale": {
            "target_dedicated_nodes": 1,
            "target_low_priority_nodes": 0,
        },
    },
    vm_size="Standard_d2s_v3")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					ImageReference: &batch.ImageReferenceArgs{
						Offer:     pulumi.String("windowsserver"),
						Publisher: pulumi.String("microsoftwindowsserver"),
						Sku:       pulumi.String("2022-datacenter-smalldisk"),
					},
					NodeAgentSkuId: pulumi.String("batch.node.windows amd64"),
					OsDisk: &batch.OSDiskArgs{
						Caching:    batch.CachingTypeReadWrite,
						DiskSizeGB: pulumi.Int(100),
						ManagedDisk: &batch.ManagedDiskArgs{
							StorageAccountType: batch.StorageAccountType_StandardSSD_LRS,
						},
						WriteAcceleratorEnabled: pulumi.Bool(false),
					},
				},
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			ScaleSettings: &batch.ScaleSettingsArgs{
				FixedScale: &batch.FixedScaleSettingsArgs{
					TargetDedicatedNodes:   pulumi.Int(1),
					TargetLowPriorityNodes: pulumi.Int(0),
				},
			},
			VmSize: pulumi.String("Standard_d2s_v3"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Offer = "windowsserver",
                    Publisher = "microsoftwindowsserver",
                    Sku = "2022-datacenter-smalldisk",
                },
                NodeAgentSkuId = "batch.node.windows amd64",
                OsDisk = new AzureNative.Batch.Inputs.OSDiskArgs
                {
                    Caching = AzureNative.Batch.CachingType.ReadWrite,
                    DiskSizeGB = 100,
                    ManagedDisk = new AzureNative.Batch.Inputs.ManagedDiskArgs
                    {
                        StorageAccountType = AzureNative.Batch.StorageAccountType.StandardSSD_LRS,
                    },
                    WriteAcceleratorEnabled = false,
                },
            },
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        ScaleSettings = new AzureNative.Batch.Inputs.ScaleSettingsArgs
        {
            FixedScale = new AzureNative.Batch.Inputs.FixedScaleSettingsArgs
            {
                TargetDedicatedNodes = 1,
                TargetLowPriorityNodes = 0,
            },
        },
        VmSize = "Standard_d2s_v3",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import com.pulumi.azurenative.batch.inputs.OSDiskArgs;
import com.pulumi.azurenative.batch.inputs.ManagedDiskArgs;
import com.pulumi.azurenative.batch.inputs.ScaleSettingsArgs;
import com.pulumi.azurenative.batch.inputs.FixedScaleSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .imageReference(ImageReferenceArgs.builder()
                        .offer("windowsserver")
                        .publisher("microsoftwindowsserver")
                        .sku("2022-datacenter-smalldisk")
                        .build())
                    .nodeAgentSkuId("batch.node.windows amd64")
                    .osDisk(OSDiskArgs.builder()
                        .caching("ReadWrite")
                        .diskSizeGB(100)
                        .managedDisk(ManagedDiskArgs.builder()
                            .storageAccountType("StandardSSD_LRS")
                            .build())
                        .writeAcceleratorEnabled(false)
                        .build())
                    .build())
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .scaleSettings(ScaleSettingsArgs.builder()
                .fixedScale(FixedScaleSettingsArgs.builder()
                    .targetDedicatedNodes(1)
                    .targetLowPriorityNodes(0)
                    .build())
                .build())
            .vmSize("Standard_d2s_v3")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          imageReference:
            offer: windowsserver
            publisher: microsoftwindowsserver
            sku: 2022-datacenter-smalldisk
          nodeAgentSkuId: batch.node.windows amd64
          osDisk:
            caching: ReadWrite
            diskSizeGB: 100
            managedDisk:
              storageAccountType: StandardSSD_LRS
            writeAcceleratorEnabled: false
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      scaleSettings:
        fixedScale:
          targetDedicatedNodes: 1
          targetLowPriorityNodes: 0
      vmSize: Standard_d2s_v3

The extensions array installs Azure VM extensions on each node. Each extension specifies a publisher, type, and settings object. Here, the KeyVaultForLinux extension injects secrets from Key Vault. Extensions run during node provisioning, before tasks execute.

Deploy nodes without public IP addresses

Workloads that access only private resources can disable public IPs to reduce attack surface and simplify network security.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            imageReference: {
                id: "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
            },
            nodeAgentSkuId: "batch.node.ubuntu 18.04",
        },
    },
    networkConfiguration: {
        publicIPAddressConfiguration: {
            provision: azure_native.batch.IPAddressProvisioningType.NoPublicIPAddresses,
        },
        subnetId: "/subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123",
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    vmSize: "STANDARD_D4",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "image_reference": {
                "id": "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
            },
            "node_agent_sku_id": "batch.node.ubuntu 18.04",
        },
    },
    network_configuration={
        "public_ip_address_configuration": {
            "provision": azure_native.batch.IPAddressProvisioningType.NO_PUBLIC_IP_ADDRESSES,
        },
        "subnet_id": "/subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123",
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    vm_size="STANDARD_D4")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					ImageReference: &batch.ImageReferenceArgs{
						Id: pulumi.String("/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1"),
					},
					NodeAgentSkuId: pulumi.String("batch.node.ubuntu 18.04"),
				},
			},
			NetworkConfiguration: &batch.NetworkConfigurationArgs{
				PublicIPAddressConfiguration: &batch.PublicIPAddressConfigurationArgs{
					Provision: batch.IPAddressProvisioningTypeNoPublicIPAddresses,
				},
				SubnetId: pulumi.String("/subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123"),
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			VmSize:            pulumi.String("STANDARD_D4"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Id = "/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1",
                },
                NodeAgentSkuId = "batch.node.ubuntu 18.04",
            },
        },
        NetworkConfiguration = new AzureNative.Batch.Inputs.NetworkConfigurationArgs
        {
            PublicIPAddressConfiguration = new AzureNative.Batch.Inputs.PublicIPAddressConfigurationArgs
            {
                Provision = AzureNative.Batch.IPAddressProvisioningType.NoPublicIPAddresses,
            },
            SubnetId = "/subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123",
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        VmSize = "STANDARD_D4",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import com.pulumi.azurenative.batch.inputs.NetworkConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.PublicIPAddressConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .imageReference(ImageReferenceArgs.builder()
                        .id("/subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1")
                        .build())
                    .nodeAgentSkuId("batch.node.ubuntu 18.04")
                    .build())
                .build())
            .networkConfiguration(NetworkConfigurationArgs.builder()
                .publicIPAddressConfiguration(PublicIPAddressConfigurationArgs.builder()
                    .provision("NoPublicIPAddresses")
                    .build())
                .subnetId("/subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123")
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .vmSize("STANDARD_D4")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          imageReference:
            id: /subscriptions/subid/resourceGroups/networking-group/providers/Microsoft.Compute/galleries/testgallery/images/testimagedef/versions/0.0.1
          nodeAgentSkuId: batch.node.ubuntu 18.04
      networkConfiguration:
        publicIPAddressConfiguration:
          provision: NoPublicIPAddresses
        subnetId: /subscriptions/subid/resourceGroups/rg1234/providers/Microsoft.Network/virtualNetworks/network1234/subnets/subnet123
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      vmSize: STANDARD_D4

The publicIPAddressConfiguration property controls IP provisioning. Setting provision to NoPublicIPAddresses prevents Batch from assigning public IPs. The subnetId places nodes in a VNet subnet. Nodes can still communicate with Batch service endpoints through private connectivity or service endpoints.

Enable automatic OS upgrades with rolling updates

Long-running pools benefit from automatic OS patching to stay current without manual intervention or full pool replacement.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const pool = new azure_native.batch.Pool("pool", {
    accountName: "sampleacct",
    deploymentConfiguration: {
        virtualMachineConfiguration: {
            extensions: [{
                autoUpgradeMinorVersion: true,
                enableAutomaticUpgrade: true,
                name: "batchextension1",
                publisher: "Microsoft.Azure.KeyVault",
                settings: {
                    authenticationSettingsKey: "authenticationSettingsValue",
                    secretsManagementSettingsKey: "secretsManagementSettingsValue",
                },
                type: "KeyVaultForLinux",
                typeHandlerVersion: "2.0",
            }],
            imageReference: {
                offer: "0001-com-ubuntu-server-focal",
                publisher: "Canonical",
                sku: "20_04-lts",
            },
            nodeAgentSkuId: "batch.node.ubuntu 20.04",
        },
    },
    poolName: "testpool",
    resourceGroupName: "default-azurebatch-japaneast",
    scaleSettings: {
        autoScale: {
            evaluationInterval: "PT5M",
            formula: "$TargetDedicatedNodes=1",
        },
    },
    targetNodeCommunicationMode: azure_native.batch.NodeCommunicationMode.Default,
    vmSize: "STANDARD_D4",
});
import pulumi
import pulumi_azure_native as azure_native

pool = azure_native.batch.Pool("pool",
    account_name="sampleacct",
    deployment_configuration={
        "virtual_machine_configuration": {
            "extensions": [{
                "auto_upgrade_minor_version": True,
                "enable_automatic_upgrade": True,
                "name": "batchextension1",
                "publisher": "Microsoft.Azure.KeyVault",
                "settings": {
                    "authenticationSettingsKey": "authenticationSettingsValue",
                    "secretsManagementSettingsKey": "secretsManagementSettingsValue",
                },
                "type": "KeyVaultForLinux",
                "type_handler_version": "2.0",
            }],
            "image_reference": {
                "offer": "0001-com-ubuntu-server-focal",
                "publisher": "Canonical",
                "sku": "20_04-lts",
            },
            "node_agent_sku_id": "batch.node.ubuntu 20.04",
        },
    },
    pool_name="testpool",
    resource_group_name="default-azurebatch-japaneast",
    scale_settings={
        "auto_scale": {
            "evaluation_interval": "PT5M",
            "formula": "$TargetDedicatedNodes=1",
        },
    },
    target_node_communication_mode=azure_native.batch.NodeCommunicationMode.DEFAULT,
    vm_size="STANDARD_D4")
package main

import (
	batch "github.com/pulumi/pulumi-azure-native-sdk/batch/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := batch.NewPool(ctx, "pool", &batch.PoolArgs{
			AccountName: pulumi.String("sampleacct"),
			DeploymentConfiguration: &batch.DeploymentConfigurationArgs{
				VirtualMachineConfiguration: &batch.VirtualMachineConfigurationArgs{
					Extensions: batch.VMExtensionArray{
						&batch.VMExtensionArgs{
							AutoUpgradeMinorVersion: pulumi.Bool(true),
							EnableAutomaticUpgrade:  pulumi.Bool(true),
							Name:                    pulumi.String("batchextension1"),
							Publisher:               pulumi.String("Microsoft.Azure.KeyVault"),
							Settings: pulumi.Any(map[string]interface{}{
								"authenticationSettingsKey":    "authenticationSettingsValue",
								"secretsManagementSettingsKey": "secretsManagementSettingsValue",
							}),
							Type:               pulumi.String("KeyVaultForLinux"),
							TypeHandlerVersion: pulumi.String("2.0"),
						},
					},
					ImageReference: &batch.ImageReferenceArgs{
						Offer:     pulumi.String("0001-com-ubuntu-server-focal"),
						Publisher: pulumi.String("Canonical"),
						Sku:       pulumi.String("20_04-lts"),
					},
					NodeAgentSkuId: pulumi.String("batch.node.ubuntu 20.04"),
				},
			},
			PoolName:          pulumi.String("testpool"),
			ResourceGroupName: pulumi.String("default-azurebatch-japaneast"),
			ScaleSettings: &batch.ScaleSettingsArgs{
				AutoScale: &batch.AutoScaleSettingsArgs{
					EvaluationInterval: pulumi.String("PT5M"),
					Formula:            pulumi.String("$TargetDedicatedNodes=1"),
				},
			},
			TargetNodeCommunicationMode: batch.NodeCommunicationModeDefault,
			VmSize:                      pulumi.String("STANDARD_D4"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var pool = new AzureNative.Batch.Pool("pool", new()
    {
        AccountName = "sampleacct",
        DeploymentConfiguration = new AzureNative.Batch.Inputs.DeploymentConfigurationArgs
        {
            VirtualMachineConfiguration = new AzureNative.Batch.Inputs.VirtualMachineConfigurationArgs
            {
                Extensions = new[]
                {
                    new AzureNative.Batch.Inputs.VMExtensionArgs
                    {
                        AutoUpgradeMinorVersion = true,
                        EnableAutomaticUpgrade = true,
                        Name = "batchextension1",
                        Publisher = "Microsoft.Azure.KeyVault",
                        Settings = new Dictionary<string, object?>
                        {
                            ["authenticationSettingsKey"] = "authenticationSettingsValue",
                            ["secretsManagementSettingsKey"] = "secretsManagementSettingsValue",
                        },
                        Type = "KeyVaultForLinux",
                        TypeHandlerVersion = "2.0",
                    },
                },
                ImageReference = new AzureNative.Batch.Inputs.ImageReferenceArgs
                {
                    Offer = "0001-com-ubuntu-server-focal",
                    Publisher = "Canonical",
                    Sku = "20_04-lts",
                },
                NodeAgentSkuId = "batch.node.ubuntu 20.04",
            },
        },
        PoolName = "testpool",
        ResourceGroupName = "default-azurebatch-japaneast",
        ScaleSettings = new AzureNative.Batch.Inputs.ScaleSettingsArgs
        {
            AutoScale = new AzureNative.Batch.Inputs.AutoScaleSettingsArgs
            {
                EvaluationInterval = "PT5M",
                Formula = "$TargetDedicatedNodes=1",
            },
        },
        TargetNodeCommunicationMode = AzureNative.Batch.NodeCommunicationMode.Default,
        VmSize = "STANDARD_D4",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.batch.Pool;
import com.pulumi.azurenative.batch.PoolArgs;
import com.pulumi.azurenative.batch.inputs.DeploymentConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.VirtualMachineConfigurationArgs;
import com.pulumi.azurenative.batch.inputs.ImageReferenceArgs;
import com.pulumi.azurenative.batch.inputs.ScaleSettingsArgs;
import com.pulumi.azurenative.batch.inputs.AutoScaleSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var pool = new Pool("pool", PoolArgs.builder()
            .accountName("sampleacct")
            .deploymentConfiguration(DeploymentConfigurationArgs.builder()
                .virtualMachineConfiguration(VirtualMachineConfigurationArgs.builder()
                    .extensions(VMExtensionArgs.builder()
                        .autoUpgradeMinorVersion(true)
                        .enableAutomaticUpgrade(true)
                        .name("batchextension1")
                        .publisher("Microsoft.Azure.KeyVault")
                        .settings(Map.ofEntries(
                            Map.entry("authenticationSettingsKey", "authenticationSettingsValue"),
                            Map.entry("secretsManagementSettingsKey", "secretsManagementSettingsValue")
                        ))
                        .type("KeyVaultForLinux")
                        .typeHandlerVersion("2.0")
                        .build())
                    .imageReference(ImageReferenceArgs.builder()
                        .offer("0001-com-ubuntu-server-focal")
                        .publisher("Canonical")
                        .sku("20_04-lts")
                        .build())
                    .nodeAgentSkuId("batch.node.ubuntu 20.04")
                    .build())
                .build())
            .poolName("testpool")
            .resourceGroupName("default-azurebatch-japaneast")
            .scaleSettings(ScaleSettingsArgs.builder()
                .autoScale(AutoScaleSettingsArgs.builder()
                    .evaluationInterval("PT5M")
                    .formula("$TargetDedicatedNodes=1")
                    .build())
                .build())
            .targetNodeCommunicationMode("Default")
            .vmSize("STANDARD_D4")
            .build());

    }
}
resources:
  pool:
    type: azure-native:batch:Pool
    properties:
      accountName: sampleacct
      deploymentConfiguration:
        virtualMachineConfiguration:
          extensions:
            - autoUpgradeMinorVersion: true
              enableAutomaticUpgrade: true
              name: batchextension1
              publisher: Microsoft.Azure.KeyVault
              settings:
                authenticationSettingsKey: authenticationSettingsValue
                secretsManagementSettingsKey: secretsManagementSettingsValue
              type: KeyVaultForLinux
              typeHandlerVersion: '2.0'
          imageReference:
            offer: 0001-com-ubuntu-server-focal
            publisher: Canonical
            sku: 20_04-lts
          nodeAgentSkuId: batch.node.ubuntu 20.04
      poolName: testpool
      resourceGroupName: default-azurebatch-japaneast
      scaleSettings:
        autoScale:
          evaluationInterval: PT5M
          formula: $TargetDedicatedNodes=1
      targetNodeCommunicationMode: Default
      vmSize: STANDARD_D4

The upgradePolicy defines how Batch applies OS updates. Setting mode to Automatic enables automatic upgrades. The automaticOSUpgradePolicy controls rollback and deferral behavior. The rollingUpgradePolicy limits how many nodes upgrade simultaneously (maxBatchInstancePercent) and defines pause times between batches. This keeps pools patched while maintaining workload availability.

Beyond these examples

These snippets focus on specific pool-level features: image selection and autoscaling, storage and network endpoints, and VM extensions and OS upgrade policies. They’re intentionally minimal rather than full Batch deployments.

The examples may reference pre-existing infrastructure such as Azure Batch accounts, Azure Compute Gallery images for custom image examples, and VNet subnets for network configuration examples. They focus on configuring the pool rather than provisioning the surrounding infrastructure.

To keep things focused, common pool patterns are omitted, including:

  • Start tasks and application packages
  • Mount configurations (Azure Files, NFS, Blobfuse)
  • User accounts and task scheduling policies
  • Certificates and identity configuration

These omissions are intentional: the goal is to illustrate how each pool feature is wired, not provide drop-in compute modules. See the Batch Pool resource reference for all available configuration options.

Let's deploy Azure Batch Pools

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

VM Configuration & Images
How do I specify a custom image vs a marketplace image for my pool?
For custom images, set imageReference.id to your Azure Compute Gallery image resource ID. For marketplace images, specify publisher, offer, sku, and version in imageReference.
What is nodeAgentSkuId and how do I choose the right one?
nodeAgentSkuId identifies the Batch node agent compatible with your OS. Use batch.node.ubuntu 18.04 for Ubuntu 18.04, batch.node.windows amd64 for Windows Server, etc. It must match your image’s OS.
What are the limits for taskSlotsPerNode?
taskSlotsPerNode defaults to 1 and has a maximum of the smaller of 4 times the VM’s core count or 256.
Scaling & Node Management
What's the difference between autoScale and fixedScale?
autoScale uses a formula (e.g., $TargetDedicatedNodes=1) evaluated at intervals to dynamically adjust node count. fixedScale sets static targetDedicatedNodes and targetLowPriorityNodes values.
What happens if I don't specify scaleSettings?
The pool defaults to fixedScale with 0 targetDedicatedNodes.
Networking
How do I control public IP addresses for pool nodes?
Set publicIPAddressConfiguration.provision to NoPublicIPAddresses to disable public IPs, or UserManaged with ipAddressIds to specify your own public IP resources.
How do I connect my pool to a virtual network?
Set networkConfiguration.subnetId to your VNet subnet resource ID.
How do I enable accelerated networking?
Set networkConfiguration.enableAcceleratedNetworking to true and provide a subnetId.
Storage & Disks
How do I encrypt OS and temporary disks?
Configure diskEncryptionConfiguration.targets with OsDisk and/or TemporaryDisk.
How do I attach data disks to pool nodes?
Add entries to virtualMachineConfiguration.dataDisks with lun, diskSizeGB, caching, and storageAccountType.
How do I use ephemeral OS disks for better performance?
Configure osDisk.ephemeralOSDiskSettings.placement (e.g., CacheDisk) to place the OS disk on the VM’s cache or temporary disk.
Security & Identity
Why shouldn't I use the certificates property?
The certificates property is deprecated and will be removed after February 2024. Use the Azure KeyVault Extension for certificate management instead.
What's the difference between resourceTags and tags?
resourceTags propagate to backing Azure resources like VMs and disks, while tags apply only to the pool resource itself. resourceTags require the Batch account to use UserSubscription poolAllocationMode.
Upgrades & Extensions
How do I configure automatic OS upgrades?
Set upgradePolicy.mode to automatic and configure automaticOSUpgradePolicy settings like enableAutomaticOSUpgrade and useRollingUpgradePolicy.
How do I add VM extensions to pool nodes?
Add entries to virtualMachineConfiguration.extensions with name, publisher, type, typeHandlerVersion, and optional settings.

Using a different cloud?

Explore compute guides for other cloud providers: