Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This quickstart shows how to deploy a Kubernetes cluster in Azure Kubernetes Service (AKS) Arc using an Azure Resource Manager template (ARM template) on Azure Local for multi-rack deployments. Azure Arc extends Azure management capabilities to Kubernetes clusters anywhere, providing a unified approach to managing different environments.
Before you begin
This article assumes a basic understanding of Kubernetes concepts.
To deploy an ARM template, you need write access on the resources you're deploying, and access to all operations on the Microsoft.Resources/deployments resource type. For example, to deploy a virtual machine, you need Microsoft.Compute/virtualMachines/write and Microsoft.Resources/deployments/* permissions. For a list of roles and permissions, see Azure built-in roles.
Prerequisites
- An Azure account with an active subscription.
- An Azure Local cluster, with a target custom location for the AKS Arc cluster.
- The latest version of Azure CLI.
- A logical network provisioned. For more information, see Network requirements.
Step 1: Prepare your Azure account
Sign in to Azure: open your terminal or command prompt and sign in to your Azure account using the Azure CLI:
az loginSet your subscription: replace
<your-subscription-id>with your subscription ID:az account set --subscription "<your-subscription-id>"
Step 2: Create an SSH key pair
Create an SSH key pair in Azure and store the private key file for troubleshooting and log collection purposes. For detailed instructions, see Configure SSH keys for an AKS cluster to create SSH keys, or use Restrict SSH access during cluster creation. To access nodes afterward, see Connect to Windows or Linux worker nodes with SSH.
Open a Cloud Shell session in your web browser or launch a terminal on your local machine.
Create an SSH key pair using the az sshkey create command:
az sshkey create --name "mySSHKey" --resource-group $<resource_group_name>or, use the
ssh-keygencommand:ssh-keygen -t rsa -b 4096Retrieve the value of your public key from Azure or from your local machine under ~/.ssh/id_rsa.pub.
Step 3: Gather key details
Make sure you have the following details for the ARM template:
Custom location associated with the Azure Local instance you want to deploy AKS Arc cluster on
Azure Resource Manager resource ID of the logical network you want to use for your AKS Arc cluster, with sufficient IP addresses. For more information, see IP address planning.
Desired Kubernetes version for your environment. You can query the available Kubernetes versions for your environment using:
az aksarc get-versions --custom-location "/subscriptions/<your-subscription-id>/providers/Microsoft.ExtendedLocation/customLocations/<your-custom-location>" -o table
Step 4: Prepare the template
The ARM template used in this quickstart creates two resources:
Microsoft.Kubernetes/ConnectedClusters: An Arc-enabled Kubernetes cluster resource that represents the cluster in Azure.microsoft.hybridcontainerservice/provisionedclusterinstances: The provisioned cluster instance that defines the cluster configuration, including node pools, networking, and Kubernetes version.
The following code is a sample template you can use:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string"
},
"customLocation": {
"type": "string"
},
"vnetSubnetIds": {
"type": "array"
},
"connectedClusterName": {
"type": "string"
},
"sshRSAPublicKey": {
"type": "string"
},
"controlPlaneIp": {
"type": "string"
},
"kubernetesVersion": {
"type": "string"
},
"controlPlaneVMSize": {
"type": "string"
},
"controlPlaneNodeCount": {
"type": "int"
},
"agentName": {
"type": "string"
},
"agentVMSize": {
"type": "string"
},
"agentOsType": {
"allowedValues": [
"Linux",
"Windows"
],
"type": "string"
},
"agentCount": {
"type": "int"
},
"networkPolicy": {
"type": "string"
},
"podCidr": {
"type": "string"
},
"loadBalancerCount": {
"type": "int"
},
"connectedClustersApiVersion":{
"type": "string"
},
"provisionedClustersApiVersion": {
"type": "string"
},
"nodepoolLabel":{
"type": "string"
},
"nodepoolLabelValue":{
"type": "string"
},
"nodepoolTaints":{
"type": "array",
"defaultValue": []
},
"enableAzureHybridBenefit": {
"type": "string",
"allowedValues": [
"True",
"False"
]
},
"enableNfsCsiDriver": {
"type": "bool"
},
"enableSmbCsiDriver": {
"type": "bool"
},
"enableWorkloadIdentity": {
"type": "bool",
"defaultValue": false
},
"enableOidcIssuer": {
"type": "bool",
"defaultValue": false
}
},
"resources": [
{
"type": "Microsoft.Kubernetes/connectedClusters",
"apiVersion": "[parameters('connectedClustersApiVersion')]",
"name": "[parameters('connectedClusterName')]",
"location": "[parameters('location')]",
"kind": "ProvisionedCluster",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"agentPublicKeyCertificate": "",
"aadProfile": {
"enableAzureRBAC": false
},
"securityProfile": {
"workloadIdentity": {
"enabled": "[parameters('enableWorkloadIdentity')]"
}
},
"oidcIssuerProfile": {
"enabled": "[parameters('enableOidcIssuer')]"
}
}
},
{
"type": "Microsoft.HybridContainerService/provisionedClusterInstances",
"apiVersion": "[parameters('provisionedClustersApiVersion')]",
"name": "default",
"extendedLocation": {
"type": "CustomLocation",
"name": "[parameters('customLocation')]"
},
"dependsOn": [
"[resourceId('Microsoft.Kubernetes/connectedClusters', parameters('connectedClusterName'))]"
],
"properties": {
"kubernetesVersion": "[parameters('kubernetesVersion')]",
"linuxProfile": {
"ssh": {
"publicKeys": [
{
"keyData": "[parameters('sshRSAPublicKey')]"
}
]
}
},
"controlPlane": {
"count": "[parameters('controlPlaneNodeCount')]",
"controlPlaneEndpoint": {
"hostIP": "[parameters('controlPlaneIp')]"
},
"vmSize": "[parameters('controlPlaneVMSize')]"
},
"networkProfile": {
"networkPolicy": "[parameters('networkPolicy')]",
"loadBalancerProfile": {
"count": "[parameters('loadBalancerCount')]"
},
"podCidr": "[parameters('podCidr')]"
},
"agentPoolProfiles": [
{
"name": "[parameters('agentName')]",
"count": "[parameters('agentCount')]",
"vmSize": "[parameters('agentVMSize')]",
"osType": "[parameters('agentOsType')]",
"nodeLabels": "[if(not(empty(parameters('nodepoolLabel'))), createObject(parameters('nodepoolLabel'), parameters('nodepoolLabelValue')), json('null'))]",
"nodeTaints": "[if(greater(length(parameters('nodepoolTaints')), 0), parameters('nodepoolTaints'), json('null'))]"
}
],
"cloudProviderProfile": {
"infraNetworkProfile": {
"vnetSubnetIds": "[parameters('vnetSubnetIds')]"
}
},
"licenseProfile": {
"azureHybridBenefit": "[parameters('enableAzureHybridBenefit')]"
},
"storageProfile": {
"nfsCsiDriver": {
"enabled": "[parameters('enableNfsCsiDriver')]"
},
"smbCsiDriver": {
"enabled": "[parameters('enableSmbCsiDriver')]"
}
}
},
"scope": "[format('Microsoft.Kubernetes/connectedClusters/{0}', parameters('connectedClusterName'))]"
}
]
}
Configure the parameters
Save the following parameter file and update the placeholder values with your environment information:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"value": "eastus"
},
"customLocation": {
"value": "/subscriptions/<your-subscription-id>/resourcegroups/<your-resource-group>/providers/microsoft.extendedlocation/customlocations/<your-custom-location>"
},
"vnetSubnetIds": {
"value": [
"/subscriptions/<your-subscription-id>/resourcegroups/<your-resource-group>/providers/Microsoft.AzureStackHCI/logicalNetworks/<your-lnet-name>>"
]
},
"connectedClusterName": {
"value": "aks-test"
},
"sshRSAPublicKey": {
"value": "<your-ssh-public-key>"
},
"controlPlaneIp": {
"value": ""
},
"kubernetesVersion": {
"value": "v1.33.7"
},
"controlPlaneVMSize": {
"value": "Standard_D4s_v3"
},
"controlPlaneNodeCount": {
"value": 1
},
"agentName": {
"value": "agentpool1"
},
"agentVMSize": {
"value": "Standard_D4s_v3"
},
"agentOsType": {
"value": "Linux"
},
"agentCount": {
"value": 2
},
"networkPolicy": {
"value": "calico"
},
"loadBalancerCount": {
"value": 0
},
"connectedClustersApiVersion": {
"value": "2025-12-01-preview"
},
"provisionedClustersApiVersion": {
"value": "2025-09-01-preview"
},
"nodepoolLabel": {
"value": "myown"
},
"nodepoolLabelValue": {
"value": "dingdong"
},
"nodepoolTaints": {
"value": []
},
"enableAzureHybridBenefit": {
"value": "False"
},
"enableNfsCsiDriver": {
"value": true
},
"enableSmbCsiDriver": {
"value": true
},
"enableWorkloadIdentity": {
"value": false
},
"enableOidcIssuer": {
"value": false
},
"enableOidcIssuer": {
"value": false
},
"podCidr": {
"value": "10.244.0.0/16"
}
}
}
Warning
- Ensure that Azure role-based access control (Azure RBAC) is set to
false. Azure RBAC isn't supported on AKS Azure Local for multi-rack deployments currently. - Pod CIDR is a required field. Ensure it's specified at time of cluster creation.
Parameter reference
| Parameter | Required | Description | Default |
|---|---|---|---|
provisionedClusterName |
Yes | Name for your AKS Arc cluster. | my-aksarc-cluster |
location |
Yes | Azure region. Must match the region of your Azure Local deployment. | Resource group location |
sshRSAPublicKey |
Yes | SSH public key for node access. | — |
kubernetesVersion |
Yes | Kubernetes version to deploy (for example, 1.33.7). |
— |
vnetSubnetIds |
Yes | Azure Resource Manager resource ID of the logical network. Must have DHCP enabled and /28+ subnet. | — |
customLocation |
Yes | Azure Resource Manager resource ID of the custom location. | — |
podCidr |
Yes | CIDR range for pod IPs. Must not overlap with the logical network subnet. | 10.244.0.0/16 |
controlPlaneIp |
No | This parameter must be empty during cluster creation because it's auto-allocated. For any updates, it must be provided to match the current endpoint. | "" (auto-allocate) |
Step 5: Deploy the template
Sign in to Azure CLI and set your subscription:
az login az account set --subscription "<subscription-id>"Create a resource group (or use an existing one):
az group create --name <resource-group> --location <location>Deploy the ARM template:
az deployment group create \ --resource-group <resource-group> \ --template-file <template-file>.json \ --parameters @<parameters-file>.jsonThe deployment takes several minutes to complete.
Step 6: Verify the deployment
Check the deployment status:
az deployment group show \ --name aksarc-template \ --resource-group <resource-group> \ --query "properties.provisioningState" -o tsvThe output should show
Succeeded.View the cluster details:
az aksarc show \ --name <cluster-name> \ --resource-group <resource-group> -o table
Step 7: Connect to the cluster
To connect to the cluster, run the az connectedk8s proxy command. The command downloads and runs a proxy binary on the client machine, and fetches a
kubeconfigfile associated with the cluster.az connectedk8s proxy --name <cluster name> -g <resource group>With the proxy running, you can use the Kubernetes command-line client,
kubectl. If you use Azure Cloud Shell,kubectlis already installed. To install and runkubectllocally, run az-aks-install-cli or download from the Kubernetes website.Verify the connection to your cluster using the
kubectl getcommand. This command returns a list of the cluster nodes.kubectl get nodes -A --kubeconfig .\<path to kubecofig>The following example output shows the three nodes created in the previous steps. Make sure the node status is
Ready.NAME STATUS ROLES AGE VERSION haks-9be0b433-control-plane-tvmbn Ready control-plane 106m v1.33.7 haks-9be0b433-nodepool1-md-64scc-gfknc Ready <none> 102m v1.33.7 haks-9be0b433-nodepool1-md-64scc-m9lqp Ready <none> 102m v1.33.7