Create a node pool in Azure Red Hat OpenShift with hosted control planes (preview)

After creating an Azure Red Hat OpenShift with hosted control planes cluster, you can create node pools to add compute capacity. A node pool is a group of compute nodes that share the same configuration. You can add multiple node pools to a single cluster, so you can mix different node types and sizes to suit your workloads.

Most node pool properties are immutable after creation. Review the Node pool properties reference carefully before creating a node pool. To change an immutable property like VM size, disk configuration, subnet, or availability zone, you must delete the node pool and create a new one.

Prerequisites

Set environment variables

If you didn't already set the following environment variables, set them in your shell before proceeding. Replace the placeholder values with your own.

LOCATION="<azure-region>"
SUBSCRIPTION_ID="$(az account show --query id --output tsv)"
CUSTOMER_RG_NAME="<resource-group-name>"
CLUSTER_NAME="<cluster-name>"
NP_NAME="<node-pool-name>"
NP_VERSION="<node-pool-version>"

Note

For a list of the supported regions, see Choose the cluster region.

(Optional) Set up OS disk encryption

Azure Red Hat OpenShift with hosted control planes supports two optional encryption methods for node pool OS disks. Both methods are immutable after node pool creation, and you can combine them on the same node pool.

  • Customer-managed key (CMK) encryption uses an Azure Disk Encryption Set that references a key in your Azure Key Vault to encrypt OS disks.
  • Encryption at host provides end-to-end encryption for VM data. Data stored on the VM host is encrypted at rest and flows encrypted to the Storage service.

If you don't need either encryption option, skip to Create the node pool.

Create a disk encryption set

To encrypt node pool OS disks by using customer-managed keys, create an Azure Disk Encryption Set that references a key in your Key Vault. Then, reference the Disk Encryption Set when you create the node pool.
The Disk Encryption Set must be in the same subscription and location as the cluster.

Note

Disk Encryption Sets encrypt node pool OS disks. This feature is independent of etcd encryption, which encrypts cluster state data at rest. For information about etcd encryption, see Choose the cluster encryption strategy.

Important

You're responsible for maintaining the Key Vault and Disk Encryption Set in Azure.
If you don't maintain the keys, the node pools that use those keys break.
The VMs stop working and, as a result, any workloads running on the affected nodes stop functioning. Red Hat Site Reliability Engineering (SRE) can't access, back up, replicate, or retrieve your keys.

  1. Set environment variables for the disk encryption resources. Replace the placeholder values with your own.

    KEYVAULT_NAME="<key-vault-name>"
    KEYVAULT_KEY_NAME="<key-name>"
    DISK_ENCRYPTION_SET_NAME="<disk-encryption-set-name>"
    
  2. Create a Key Vault with purge protection enabled to store your encryption key. Purge protection prevents a deleted vault from being permanently removed before the retention period expires, which protects against accidental or malicious deletion.

    az keyvault create \
        --name $KEYVAULT_NAME \
        --resource-group $CUSTOMER_RG_NAME \
        --location $LOCATION \
        --enable-purge-protection true
    

    Note

    Purge protection is required and can't be disabled after it's enabled. By default, a deleted vault is retained for 90 days. To allow quicker name reclamation, add --retention-days <number-of-days> (minimum 7 days).

  3. Create an encryption key in the Key Vault.

    az keyvault key create \
        --vault-name $KEYVAULT_NAME \
        --name $KEYVAULT_KEY_NAME \
        --protection software
    
  4. Get the Key Vault resource ID and key URL.

    KEYVAULT_ID=$(az keyvault show --name $KEYVAULT_NAME --query "[id]" -o tsv)
    KEYVAULT_KEY_URL=$(az keyvault key show --vault-name $KEYVAULT_NAME --name $KEYVAULT_KEY_NAME --query "[key.kid]" -o tsv)
    
  5. Create the Disk Encryption Set.

    az disk-encryption-set create \
        --name $DISK_ENCRYPTION_SET_NAME \
        --location $LOCATION \
        --resource-group $CUSTOMER_RG_NAME \
        --source-vault $KEYVAULT_ID \
        --key-url $KEYVAULT_KEY_URL
    
  6. Get the Disk Encryption Set resource ID and identity principal ID.

    DES_ID=$(az disk-encryption-set show --name $DISK_ENCRYPTION_SET_NAME --resource-group $CUSTOMER_RG_NAME --query 'id' -o tsv)
    DES_IDENTITY=$(az disk-encryption-set show --name $DISK_ENCRYPTION_SET_NAME --resource-group $CUSTOMER_RG_NAME --query "[identity.principalId]" -o tsv)
    
  7. Grant the Disk Encryption Set's managed identity access to the Key Vault. The following command assigns the Key Vault Crypto Service Encryption User role, which provides the required wrapkey, unwrapkey, and get key permissions.

    az role assignment create \
        --assignee $DES_IDENTITY \
        --role "Key Vault Crypto Service Encryption User" \
        --scope $KEYVAULT_ID
    

Register encryption at host

Encryption at host provides end-to-end encryption for VM data. Data stored on the VM host is encrypted at rest and flows encrypted to the Storage service.

Before you create a node pool with encryption at host, register the EncryptionAtHost feature on your subscription if you haven't already:

az feature register --namespace Microsoft.Compute --name EncryptionAtHost

Check the registration status:

az feature show --namespace Microsoft.Compute --name EncryptionAtHost

Create the node pool

Important

The network security group (NSG) associated with the subnet where the node pool workers are deployed, and the NSG associated with the VNet integration subnet must allow the traffic described in Required network security group traffic. If the NSG has a Deny rule that blocks required traffic, the node pool you create stays in the Provisioning state until the operation times out.

  1. Save the following Bicep template as nodepool.bicep.

    The following example creates a node pool with two Standard_D8s_v3 nodes:

    param clusterName string
    param nodePoolName string
    param nodePoolVersion string
    
    resource cluster 'Microsoft.RedHatOpenShift/hcpOpenShiftClusters@2026-09-01-preview' existing = {
      name: clusterName
    }
    
    resource nodepool 'Microsoft.RedHatOpenShift/hcpOpenShiftClusters/nodePools@2026-09-01-preview' = {
      parent: cluster
      name: nodePoolName
      location: resourceGroup().location
      properties: {
        version: {
          id: nodePoolVersion
          channelGroup: 'stable'
        }
        platform: {
           subnetId: hcp.properties.platform.subnetId
           vmSize: 'Standard_D8s_v3'
          osDisk: {
            sizeGiB: 64
            diskStorageAccountType: 'StandardSSD_LRS'
          }
        }
        replicas: 2
      }
    }
    

    To encrypt OS disks with customer-managed keys, add the encryptionSetId property to the osDisk block and set the value to the Disk Encryption Set resource ID:

    osDisk: {
      ...
      encryptionSetId: '<disk-encryption-set-resource-id>'
    }
    

    To enable encryption at host, add the enableEncryptionAtHost property to the platform block:

    platform: {
      ...
      enableEncryptionAtHost: true
    }
    

    Note

    You can combine enableEncryptionAtHost with encryptionSetId on the same node pool to use both encryption at host and customer-managed key encryption.

  2. Deploy the Bicep file.

    az deployment group create \
      --name 'aro-hcp-nodepool' \
      --subscription "${SUBSCRIPTION_ID}" \
      --resource-group "${CUSTOMER_RG_NAME}" \
      --template-file nodepool.bicep \
      --parameters \
        clusterName="${CLUSTER_NAME}" \
        nodePoolName="${NP_NAME}" \
        nodePoolVersion="${NP_VERSION}"
    
  3. Verify that the new nodes have a Ready status.

    oc get nodes
    

    The following example output shows the nodes from two node pools. The nodes from the new node pool (np-2) are ready:

    NAME                          STATUS   ROLES    AGE     VERSION
    mycluster-np-1-722lp-6fhkr   Ready    worker   82m     v1.31.5
    mycluster-np-1-722lp-hvg7r   Ready    worker   82m     v1.31.5
    mycluster-np-2-c7d7l-fdpms   Ready    worker   3m19s   v1.31.5
    mycluster-np-2-c7d7l-rk7kt   Ready    worker   3m41s   v1.31.5
    
  1. Create the node pool.

    The following example creates a node pool with two Standard_D8s_v3 nodes:

    az aro hcp cluster nodepool create \
      --resource-group "${CUSTOMER_RG_NAME}" \
      --cluster-name "${CLUSTER_NAME}" \
      --name "${NP_NAME}" \
      --replicas 2 \
      --vm-size Standard_D8s_v3 \
      --version "${NP_VERSION}" \
      --channel-group stable
    

    To encrypt OS disks with customer-managed keys, add the --disk-encryption-set argument with the Disk Encryption Set resource ID: --disk-encryption-set "${DES_ID}

    To enable encryption at host, add --enable-encryption-at-host true. You can combine both encryption options on the same node pool by adding both arguments.

  2. Verify that the new nodes have a Ready status.

    oc get nodes
    

    The following example output shows the nodes from two node pools. The nodes from the new node pool are ready:

    NAME                          STATUS   ROLES    AGE     VERSION
    mycluster-np-1-722lp-6fhkr   Ready    worker   82m     v1.31.5
    mycluster-np-1-722lp-hvg7r   Ready    worker   82m     v1.31.5
    mycluster-np-2-c7d7l-fdpms   Ready    worker   3m19s   v1.31.5
    mycluster-np-2-c7d7l-rk7kt   Ready    worker   3m41s   v1.31.5
    

Node pool properties reference

The following table describes the node pool properties that you can configure. Properties marked as immutable can only be set when you create the node pool.

Property Description Required Immutable
name The name of the node pool. Must be 1-15 characters long, start with a letter, end with a letter or number, and contain only letters, numbers, and hyphens. Yes Yes
version.id The OpenShift version for the node pool, such as 4.22.1. Must be less than or equal to the control plane version. Yes No
version.channelGroup The OpenShift update channel. The only supported value is stable. No No
platform.vmSize The Azure VM size for the nodes. For supported sizes, see Supported virtual machine sizes. Availability also depends on the cluster's Azure location. Yes Yes
platform.subnetId The Azure resource ID of a subnet. Must belong to the same virtual network as the cluster. The NSG attached to this subnet must allow the required node pool traffic. Defaults to the cluster's subnet if not specified. No Yes
platform.availabilityZone The availability zone for the node pool. If not specified, the node pool is created in an availability set. Only one node pool can be deployed per availability zone. For more information, see What are availability zones? No Yes
platform.osDisk.sizeGiB The OS disk size in GiB. Minimum value is 64. Default is 64 GiB. No Yes
platform.osDisk.diskStorageAccountType The managed disk type. Valid values: Premium_LRS, StandardSSD_LRS, Standard_LRS. Default is Premium_LRS. For more information, see Azure managed disk types. No Yes
platform.osDisk.diskType The type of OS disk. Managed stores the disk as an Azure managed disk. Ephemeral stores the disk on local VM storage for lower latency and faster node operations. Ephemeral disks require a VM size with local storage capacity equal to or greater than the OS disk image size. Default is Managed. For more information, see Ephemeral OS disks for Azure VMs. No Yes
platform.osDisk.encryptionSetId The Azure resource ID of a DiskEncryptionSet to encrypt OS disks. Must be in the same subscription and location as the cluster. See Create a disk encryption set. No Yes
platform.enableEncryptionAtHost Enables encryption on the VM host for all nodes in the node pool. Default is false. See Register encryption at host. No Yes
replicas The number of nodes to provision. Required if autoScaling isn't configured. Minimum value is 0. Conditional No
autoScaling Enables autoscaling for the node pool. Required if replicas isn't configured. Set autoScaling.min and autoScaling.max to define the node count range. Conditional No
labels Kubernetes labels applied as key-value pairs to newly created nodes. No No
taints Kubernetes taints applied to newly created nodes. Each taint requires a key and effect. Valid effects: NoSchedule, PreferNoSchedule, NoExecute. No No
nodeDrainTimeoutMinutes Grace period in minutes for Pod Disruption Budget-protected workloads during node replacement. Range: 0-10080 (1 week). Value 0 means no time limit. Overrides the cluster-level default. No No

Note

Azure Red Hat OpenShift with hosted control planes supports a maximum of 500 worker nodes per cluster across all node pools. Node pools deployed in an availability zone support up to 500 nodes per node pool. Node pools deployed in an availability set support up to 200 nodes per node pool.

Next steps