From 305aa0959400593bcc3efb0ae25b50e75e98f9db Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Mon, 31 Aug 2026 17:33:50 +0200 Subject: [PATCH 1/2] Add Azure Kubernetes Services (AKS) documentation --- src/content/docs/azure/services/aks.mdx | 399 ++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 src/content/docs/azure/services/aks.mdx diff --git a/src/content/docs/azure/services/aks.mdx b/src/content/docs/azure/services/aks.mdx new file mode 100644 index 00000000..c6217fd7 --- /dev/null +++ b/src/content/docs/azure/services/aks.mdx @@ -0,0 +1,399 @@ +--- +title: "Azure Kubernetes Service (AKS)" +description: Get started with Azure Kubernetes Service on LocalStack +template: doc +resourceProvider: Microsoft.ContainerService +resourceType: Microsoft.ContainerService/managedClusters +--- + +import AzureFeatureCoverage from "../../../../components/feature-coverage/AzureFeatureCoverage"; + +## Introduction + +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?](https://learn.microsoft.com/en-us/azure/aks/what-is-aks). + +LocalStack for Azure creates real, working Kubernetes clusters on your machine. `az aks create` +produces a cluster backed by [k3d](https://k3d.io/) 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](#api-coverage), which provides information on the extent +of AKS's integration with LocalStack. + +## Getting started + +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](/azure/getting-started/). Once the container is running, +enable Azure CLI interception by running: + +```bash +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: + +```bash +lstk az stop-interception +``` + +This reconfigures the `az` CLI to send commands to the official Azure management REST API. + +### Create a resource group + +Create a resource group to hold the cluster: + +```bash +az group create \ + --name rg-aks-demo \ + --location westeurope +``` + +```bash title="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 + +Create a cluster with a single node in its system node pool: + +```bash +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. + +```bash title="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", + ... +} +``` + +### Show and list clusters + +Retrieve the details of a single cluster: + +```bash +az aks show \ + --resource-group rg-aks-demo \ + --name aks-demo +``` + +```bash title="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: + +```bash +az aks list \ + --resource-group rg-aks-demo \ + --output table +``` + +```bash title="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 +``` + +### Update a cluster + +`az aks update` changes the properties of an existing cluster. The following example sets resource +tags: + +```bash +az aks update \ + --resource-group rg-aks-demo \ + --name aks-demo \ + --tags environment=local team=platform +``` + +```bash title="Output" +{ + "name": "aks-demo", + "provisioningState": "Succeeded", + "tags": { + "environment": "local", + "team": "platform" + }, + ... +} +``` + +### Connect with kubectl + +Merge the cluster credentials into your local kubeconfig: + +```bash +az aks get-credentials \ + --resource-group rg-aks-demo \ + --name aks-demo \ + --overwrite-existing +``` + +```bash title="Output" +Merged "aks-demo" as current context in /home/user/.kube/config +``` + +Query the nodes: + +```bash +kubectl get nodes +``` + +```bash title="Output" +NAME STATUS ROLES AGE VERSION +aks-nodepool1-5829393-vmss000000 Ready 99s v1.36.2+k3s1 +k3d-aks-demo-7da4c24d-server-0 Ready control-plane 2m1s v1.36.2+k3s1 +``` + +:::note +Unlike in the cloud, where the control plane is hidden, the local cluster also lists its k3d +control-plane node. Agent nodes carry the same `aks--...-vmss` naming scheme as real AKS +nodes, and the `VERSION` column reflects the underlying k3s runtime rather than the cluster's +`kubernetesVersion`. +::: + +### Manage node pools + +Add a user node pool with two nodes: + +```bash +az aks nodepool add \ + --resource-group rg-aks-demo \ + --cluster-name aks-demo \ + --name workers \ + --mode User \ + --node-count 2 +``` + +```bash title="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: + +```bash +az aks nodepool list \ + --resource-group rg-aks-demo \ + --cluster-name aks-demo \ + --output table +``` + +```bash title="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: + +```bash +az aks nodepool show \ + --resource-group rg-aks-demo \ + --cluster-name aks-demo \ + --name workers +``` + +```bash title="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: + +```bash +az aks nodepool delete \ + --resource-group rg-aks-demo \ + --cluster-name aks-demo \ + --name workers +``` + +### Stop, start, and delete + +Stop the cluster to free local resources while preserving its state: + +```bash +az aks stop \ + --resource-group rg-aks-demo \ + --name aks-demo +``` + +Verify that the cluster has stopped by confirming that `powerState` reports `Stopped`: + +```bash +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: + +```bash +az aks start \ + --resource-group rg-aks-demo \ + --name aks-demo +``` + +Delete the cluster once you are done. A deleted cluster cannot be recovered: + +```bash +az aks delete \ + --resource-group rg-aks-demo \ + --name aks-demo \ + --yes +``` + +### Teardown + +Remove the resource group and any resources it still contains: + +```bash +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: + +```bash +lstk az stop-interception +``` + +## Features + +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. + +## Cluster-creation scripts + +The [aks-samples](https://github.com/localstack-samples/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](https://github.com/localstack-samples/aks-samples/blob/main/scripts/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](https://github.com/localstack-samples/aks-samples/blob/main/scripts/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](https://github.com/localstack-samples/aks-samples/blob/main/scripts/02-install-prometheus.sh), +the [NGINX ingress controller](https://github.com/localstack-samples/aks-samples/blob/main/scripts/03-install-nginx-ingress-controller.sh), +the [Gateway API CRDs](https://github.com/localstack-samples/aks-samples/blob/main/scripts/04-install-gateway-api.sh), +[NGINX Gateway Fabric](https://github.com/localstack-samples/aks-samples/blob/main/scripts/05-install-nginx-gateway-fabric.sh), +and [cert-manager](https://github.com/localstack-samples/aks-samples/blob/main/scripts/06-install-cert-manager.sh). + +## Samples + +Every sample deploys the same Vacation Planner web application, a small Python +[Flask](https://flask.palletsprojects.com/) 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](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-sql-database) | Stores activities in an Azure SQL Database, connecting with a SQL login over TDS. | +| [web-app-mysql-flexible-server](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-mysql-flexible-server) | Stores activities in an Azure Database for MySQL flexible server. | +| [web-app-postgresql-flexible-server](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-postgresql-flexible-server) | Stores activities in an Azure Database for PostgreSQL flexible server. | +| [web-app-in-cluster-postgresql](https://github.com/localstack-samples/aks-samples/tree/main/samples/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](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-cosmosdb-mongodb-api) | Stores activities in a collection of an Azure Cosmos DB for MongoDB account. | +| [web-app-cosmosdb-nosql-api](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-cosmosdb-nosql-api) | Stores activities in a container of an Azure Cosmos DB for NoSQL account. | +| [web-app-blob-storage](https://github.com/localstack-samples/aks-samples/tree/main/samples/web-app-blob-storage) | Stores activities in an Azure Blob Storage container, using a connection string. | +| [web-app-file-storage](https://github.com/localstack-samples/aks-samples/tree/main/samples/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](https://github.com/localstack-samples/aks-samples/tree/main/samples/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. | + +## Tutorials + +The same repository includes standalone tutorials that exercise individual AKS capabilities. Unlike +the samples, they do not deploy the web application: + +| Tutorial | Description | +| -------- | ----------- | +| [policies](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/bicep/tags-labels-taints) | The same modular AKS stack built with Bicep, with parameters and outputs that mirror the Terraform tutorial one-to-one. | + +## API Coverage + + From b1e791d22301ab358fd9ca483d5eebb49de7b1dd Mon Sep 17 00:00:00 2001 From: Quetzalli Date: Wed, 9 Sep 2026 21:50:14 +0200 Subject: [PATCH 2/2] Grammar and clarity pass on AKS docs - Operations feature bullet: the nested comma list (tags, labels, and taints, the Azure cloud controller manager..., and cluster stop and start) reads as one flat list; separate the three items with semicolons since the first already contains commas. - Cluster-creation scripts intro: "The repository maintains both scripts to run against real Azure and the emulator" misplaces the modifier, on first read it sounds like the repository runs against Azure. Rephrase as "Both scripts run unchanged against real Azure and the emulator." - KEDA tutorial description: add the missing comma before "and" where it joins two independent clauses ("a producer creates..." / "a ScaledObject scales..."). Co-Authored-By: Claude Sonnet 5 --- src/content/docs/azure/services/aks.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/docs/azure/services/aks.mdx b/src/content/docs/azure/services/aks.mdx index c6217fd7..e0da72f9 100644 --- a/src/content/docs/azure/services/aks.mdx +++ b/src/content/docs/azure/services/aks.mdx @@ -334,17 +334,17 @@ The local control plane implements the following capabilities: 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. +- **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. ## Cluster-creation scripts The [aks-samples](https://github.com/localstack-samples/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: +network, a container registry, a Log Analytics workspace, and system and user node pools. Both +scripts run unchanged against real Azure and the emulator; they differ only in the cluster +identity: | Script | Cluster identity | When to use | | ------ | ---------------- | ----------- | @@ -386,7 +386,7 @@ the samples, they do not deploy the web application: | [policies](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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](https://github.com/localstack-samples/aks-samples/tree/main/tutorials/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. |