Definitions first (Bicep + Resource Group), then a precise step-by-step walkthrough of how this Bicep deploys an Azure Container Registry (ACR), an AKS cluster, and the ACR pull role assignment into a Resource Group scope.
targetScope = 'resourceGroup'.
That means it deploys resources into an existing Resource Group.
It does not create the Resource Group itself.
Creating the RG happens outside the template (for example via az group create),
then you run az deployment group create to deploy this file into that RG.
targetScope = 'resourceGroup'
@description('AKS cluster name')
param aksName string = 'aks-spring-demo'
@description('ACR name (must be globally unique, 5-50 lowercase alphanumerics)')
param acrName string
@description('Azure region')
param location string = resourceGroup().location
@description('Kubernetes version (optional). Leave empty for default.')
param kubernetesVersion string = ''
@description('AKS node VM size')
param nodeVmSize string = 'Standard_B2s'
@minValue(1)
@maxValue(3)
@description('Initial node count (keep small)')
param nodeCount int = 1
@description('DNS prefix for AKS')
param dnsPrefix string = 'springdemo'
resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: acrName
location: location
sku: {
name: 'Basic'
}
properties: {
adminUserEnabled: false
}
}
resource aks 'Microsoft.ContainerService/managedClusters@2024-01-01' = {
name: aksName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
dnsPrefix: dnsPrefix
kubernetesVersion: empty(kubernetesVersion) ? null : kubernetesVersion
agentPoolProfiles: [
{
name: 'system'
mode: 'System'
count: nodeCount
vmSize: nodeVmSize
osType: 'Linux'
type: 'VirtualMachineScaleSets'
enableAutoScaling: false
}
]
networkProfile: {
networkPlugin: 'azure'
loadBalancerSku: 'standard'
}
}
}
// Give AKS kubelet identity pull access to ACR
resource acrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(acr.id, aks.id, 'acrpull')
scope: acr
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') // AcrPull
principalId: aks.properties.identityProfile.kubeletidentity.objectId
principalType: 'ServicePrincipal'
}
}
output acrLoginServer string = acr.properties.loginServer
output aksNameOut string = aks.name
resourceGroup, Azure evaluates resourceGroup().location
and uses it as the default region unless you override location.
--parameters input.
The key required one is acrName (no default).
aksName: default aks-spring-demoacrName: required, must be globally uniquenodeCount: constrained 1..3 by decoratorskubernetesVersion: optional; empty means platform defaultMicrosoft.ContainerRegistry/registriestype: SystemAssigned means Azure creates a managed identity for the cluster resource.
Separately, AKS also creates a kubelet identity used by nodes to pull images and talk to Azure.
mode: System → system pool for core Kubernetes componentscount: nodeCount → defaults to 1 (keeps costs small)vmSize: Standard_B2s → economical for demostype: VirtualMachineScaleSets → standard AKS scaling mechanismenableAutoScaling: false → fixed node countnetworkPlugin: azure uses Azure CNI networking.
loadBalancerSku: standard selects the recommended Azure Load Balancer tier.
scope: acr).
guid(acr.id, aks.id, 'acrpull')
to generate a deterministic ID based on the resource IDs.
acrLoginServermyregistry.azurecr.io) used in image references and docker login flows.
aksNameOutaz aks get-credentials later).
az group create \
--name rg-aks-spring-demo \
--location eastus
# acrName must be globally unique
az deployment group create \
--name aks-spring-deploy \
--resource-group rg-aks-spring-demo \
--template-file main.bicep \
--parameters acrName=<uniqueacrname>