Skip to content
Get Started for Free

Azure Kubernetes Service (AKS)

Azure Kubernetes Service (AKS) is Azure’s managed Kubernetes offering. Azure operates the control plane while you manage node pools of worker machines that run your workloads. For more information, see What is Azure Kubernetes Service?.

LocalStack for Azure creates real, working Kubernetes clusters on your machine. az aks create produces a cluster backed by k3d that you can reach with kubectl, so manifests, Helm charts, and operators behave as they would against a cluster in the cloud. The supported APIs are available on our API Coverage section, which provides information on the extent of AKS’s integration with LocalStack.

This guide is designed for users new to AKS and assumes basic knowledge of the Azure CLI, kubectl, and our lstk az proxy.

Launch LocalStack using your preferred method. For more information, see Introduction to LocalStack for Azure. Once the container is running, enable Azure CLI interception by running:

Terminal window
lstk az start-interception

This command points the az CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API. To revert this configuration, run:

Terminal window
lstk az stop-interception

This reconfigures the az CLI to send commands to the official Azure management REST API.

Create a resource group to hold the cluster:

Terminal window
az group create \
--name rg-aks-demo \
--location westeurope
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-aks-demo",
"location": "westeurope",
"managedBy": null,
"name": "rg-aks-demo",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}

Create a cluster with a single node in its system node pool:

Terminal window
az aks create \
--resource-group rg-aks-demo \
--name aks-demo \
--node-count 1 \
--generate-ssh-keys

The command returns when the cluster is ready to use. Locally that takes a couple of minutes: the emulator provisions a k3d cluster, so what you get back is a live API server, not a mock.

Output
{
"currentKubernetesVersion": "1.34.4",
"fqdn": "aks-demo-rg-aks-demo-000000-oq7mpqgx.hcp.westeurope.azmk8s.io",
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-aks-demo/providers/Microsoft.ContainerService/managedClusters/aks-demo",
"kubernetesVersion": "1.34",
"location": "westeurope",
"name": "aks-demo",
"nodeResourceGroup": "MC_rg-aks-demo_aks-demo_westeurope",
"powerState": {
"code": "Running"
},
"provisioningState": "Succeeded",
...
}

Retrieve the details of a single cluster:

Terminal window
az aks show \
--resource-group rg-aks-demo \
--name aks-demo
Output
{
"currentKubernetesVersion": "1.34.4",
"dnsPrefix": "aks-demo-rg-aks-demo-000000",
"kubernetesVersion": "1.34",
"location": "westeurope",
"name": "aks-demo",
"nodeResourceGroup": "MC_rg-aks-demo_aks-demo_westeurope",
"provisioningState": "Succeeded",
...
}

List the clusters in a resource group:

Terminal window
az aks list \
--resource-group rg-aks-demo \
--output table
Output
Name Location ResourceGroup KubernetesVersion CurrentKubernetesVersion ProvisioningState Fqdn
-------- ---------- --------------- ------------------- -------------------------- ------------------- -------------------------------------------------------------
aks-demo westeurope rg-aks-demo 1.34 1.34.4 Succeeded aks-demo-rg-aks-demo-000000-oq7mpqgx.hcp.westeurope.azmk8s.io

az aks update changes the properties of an existing cluster. The following example sets resource tags:

Terminal window
az aks update \
--resource-group rg-aks-demo \
--name aks-demo \
--tags environment=local team=platform
Output
{
"name": "aks-demo",
"provisioningState": "Succeeded",
"tags": {
"environment": "local",
"team": "platform"
},
...
}

Merge the cluster credentials into your local kubeconfig:

Terminal window
az aks get-credentials \
--resource-group rg-aks-demo \
--name aks-demo \
--overwrite-existing
Output
Merged "aks-demo" as current context in /home/user/.kube/config

Query the nodes:

Terminal window
kubectl get nodes
Output
NAME STATUS ROLES AGE VERSION
aks-nodepool1-5829393-vmss000000 Ready <none> 99s v1.36.2+k3s1
k3d-aks-demo-7da4c24d-server-0 Ready control-plane 2m1s v1.36.2+k3s1

Add a user node pool with two nodes:

Terminal window
az aks nodepool add \
--resource-group rg-aks-demo \
--cluster-name aks-demo \
--name workers \
--mode User \
--node-count 2
Output
{
"count": 2,
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/rg-aks-demo/providers/Microsoft.ContainerService/managedClusters/aks-demo/agentPools/workers",
"mode": "User",
"name": "workers",
"orchestratorVersion": "1.34",
"osType": "Linux",
"provisioningState": "Succeeded",
...
}

List the node pools of the cluster:

Terminal window
az aks nodepool list \
--resource-group rg-aks-demo \
--cluster-name aks-demo \
--output table
Output
Name OsType VmSize Count MaxPods ProvisioningState Mode
--------- -------- -------- ------- --------- ------------------- ------
nodepool1 Linux 1 250 Succeeded System
workers Linux 2 250 Succeeded User

Inspect a single node pool:

Terminal window
az aks nodepool show \
--resource-group rg-aks-demo \
--cluster-name aks-demo \
--name workers
Output
{
"count": 2,
"mode": "User",
"name": "workers",
"orchestratorVersion": "1.34",
"osType": "Linux",
"powerState": {
"code": "Running"
},
"provisioningState": "Succeeded",
...
}

Delete the node pool when you no longer need it:

Terminal window
az aks nodepool delete \
--resource-group rg-aks-demo \
--cluster-name aks-demo \
--name workers

Stop the cluster to free local resources while preserving its state:

Terminal window
az aks stop \
--resource-group rg-aks-demo \
--name aks-demo

Verify that the cluster has stopped by confirming that powerState reports Stopped:

Terminal window
az aks show \
--resource-group rg-aks-demo \
--name aks-demo \
--query powerState.code \
--output tsv

Start the cluster again. It restarts with the previous control plane state and number of agent nodes:

Terminal window
az aks start \
--resource-group rg-aks-demo \
--name aks-demo

Delete the cluster once you are done. A deleted cluster cannot be recovered:

Terminal window
az aks delete \
--resource-group rg-aks-demo \
--name aks-demo \
--yes

Remove the resource group and any resources it still contains:

Terminal window
az group delete \
--name rg-aks-demo \
--yes

Disable Azure CLI interception to point the az CLI back to the official Azure management REST API:

Terminal window
lstk az stop-interception

The local control plane implements the following capabilities:

  • Networking: Azure CNI overlay with the Cilium data plane, Cilium and Calico network policies, Hubble observability, and the managed Gateway API add-on with NGINX Gateway Fabric as its implementation.
  • Storage: The Secrets Store CSI driver for Azure Key Vault and the Azure Files CSI driver. The Azure Disk CSI driver is in progress.
  • Scaling: The cluster autoscaler, node auto-provisioning based on the AKS Karpenter provider, the Kubernetes Event-driven Autoscaling (KEDA) add-on, and the Vertical Pod Autoscaler.
  • Identity: Microsoft Entra Workload ID with a working OIDC issuer, so pods can exchange service account tokens for Azure credentials without secrets.
  • Operations: Multiple node pools with tags, labels, and taints, the Azure cloud controller manager reconciling LoadBalancer services, and cluster stop and start.
  • Tooling: The same clusters can be provisioned with the Azure CLI, Terraform, or Bicep.

The aks-samples repository provides two interchangeable scripts that provision a production-shaped cluster, complete with a virtual network, a container registry, a Log Analytics workspace, and system and user node pools. The repository maintains both scripts to run against real Azure and the emulator; they differ in the cluster identity:

Script Cluster identity When to use
01-system-assigned-managed-identity.sh System-assigned managed identity Simplest option: Azure creates and manages the identity lifecycle together with the cluster.
01-user-assigned-managed-identity.sh User-assigned managed identity Use when you need a stable, pre-created identity that can be reused across resources and granted role assignments ahead of time.

Both scripts are idempotent and safe to re-run. The same folder also contains optional add-on installers for Prometheus, the NGINX ingress controller, the Gateway API CRDs, NGINX Gateway Fabric, and cert-manager.

Every sample deploys the same Vacation Planner web application, a small Python Flask single-page app. Only the data service, its provisioning, and the way the app authenticates to it change from one sample to the next.

Sample Description
web-app-sql-database Stores activities in an Azure SQL Database, connecting with a SQL login over TDS.
web-app-mysql-flexible-server Stores activities in an Azure Database for MySQL flexible server.
web-app-postgresql-flexible-server Stores activities in an Azure Database for PostgreSQL flexible server.
web-app-in-cluster-postgresql Stores activities in an in-cluster PostgreSQL database deployed as a Kubernetes StatefulSet, with a primary and two streaming replicas.
web-app-cosmosdb-mongodb-api Stores activities in a collection of an Azure Cosmos DB for MongoDB account.
web-app-cosmosdb-nosql-api Stores activities in a container of an Azure Cosmos DB for NoSQL account.
web-app-blob-storage Stores activities in an Azure Blob Storage container, using a connection string.
web-app-file-storage Stores activities as text files on an Azure Files share mounted by the Azure Files CSI driver, over either SMB or NFS.
web-app-managed-identity Stores activities in Azure Blob Storage, authenticating with Microsoft Entra Workload ID instead of a secret, and optionally exposes the app through the Gateway API with a managed TLS certificate.

The same repository includes standalone tutorials that exercise individual AKS capabilities. Unlike the samples, they do not deploy the web application:

Tutorial Description
policies Kubernetes network policies that enforce zero-trust traffic control with Calico and Cilium: cluster-wide default-deny, DNS-aware egress, and L3/L4/L7 ingress.
ccm Exercises the Azure cloud controller manager: public and internal LoadBalancer services, source ranges, the nodeIP backend-pool variant, and an NGINX ingress controller.
gateway-api Enables the managed Gateway API CRDs, installs NGINX Gateway Fabric, and routes traffic to a backend through a Gateway and an HTTPRoute.
keda Event-driven autoscaling with the KEDA add-on: a producer creates a backlog on an Azure event source and a ScaledObject scales a consumer from zero to four replicas and back.
keda/service-bus Scales a consumer on an Azure Service Bus queue with the azure-servicebus scaler, authenticating with Microsoft Entra Workload ID. Start here if you are new to KEDA.
keda/queue-storage Scales a consumer on an Azure Storage queue with the azure-queue scaler. Workload identity is used end to end, so no data-plane secret exists anywhere.
keda/event-hubs Scales a consumer on an Azure Event Hubs hub with the azure-eventhub scaler, whose backlog is the distance between the last enqueued event and the consumer group’s blob checkpoints.
key-vault-csi-driver Mounts secrets from Azure Key Vault into a pod with the Secrets Store CSI driver, in both the workload identity and the user-assigned managed identity access modes.
terraform/tags-labels-taints Deploys a modular, feature-rich AKS stack with Terraform, steering workloads across agent pools with Azure resource tags, node labels, and taints, then validates them through both the ARM and Kubernetes APIs.
bicep/tags-labels-taints The same modular AKS stack built with Bicep, with parameters and outputs that mirror the Terraform tutorial one-to-one.
OperationImplemented
Page 1 of 0
Was this page helpful?