Azure AKS + Kubernetes
This tutorial walks you through deploying a production-grade AKS cluster with Kubernetes workloads, all defined in TypeScript using two chant lexicons. The Azure lexicon produces an ARM template for infrastructure; the K8s lexicon produces kubectl-ready YAML for workloads.
What you’ll deploy
Section titled “What you’ll deploy”┌─────────────────────────────────────────────────────────┐│ Azure Lexicon (ARM) (~14 resources) ││ ├── VNet + Subnets + NSG + Route Table ││ ├── AKS Cluster (SystemAssigned identity) ││ ├── Container Registry (Premium, admin disabled) ││ ├── 3× Managed Identities (app, dns, monitor) ││ ├── Role Assignments (ACR Pull, DNS Contributor, etc.) ││ └── Azure DNS Zone │└────────────────────┬────────────────────────────────────┘ │ client IDs via .env → config.ts┌────────────────────▼────────────────────────────────────┐│ K8s Lexicon (~20 resources) ││ ├── Namespace (quotas, limits, network policy) ││ ├── AutoscaledService (Deployment + HPA + PDB) ││ ├── WorkloadIdentityServiceAccount (AKS) ││ ├── AGIC Ingress + AksExternalDnsAgent ││ ├── AzureDiskStorageClass ││ └── AzureMonitorCollector │└─────────────────────────────────────────────────────────┘| Source file | What it produces |
|---|---|
src/infra/networking.ts | VNet, 2 subnets, NSG, Route Table |
src/infra/cluster.ts | AKS cluster, ACR, 3 managed identities, role assignments |
src/infra/dns.ts | Azure DNS Zone |
src/k8s/namespace.ts | Namespace with quotas, limits, default-deny policy |
src/k8s/app.ts | AutoscaledService + WorkloadIdentityServiceAccount + ConfigMap |
src/k8s/ingress.ts | AGIC Ingress + AksExternalDnsAgent |
src/k8s/storage.ts | AzureDiskStorageClass |
src/k8s/observability.ts | AzureMonitorCollector |
src/config.ts | Cross-lexicon config — reads .env for real client IDs |
Prerequisites
Section titled “Prerequisites”- Azure account with an active subscription
- Azure CLI (
az) logged in (az account showshould work) - kubectl installed
- Bun runtime and chant installed (Installation guide)
- Subscription must have
Microsoft.ContainerService,Microsoft.Network,Microsoft.ManagedIdentity,Microsoft.ContainerRegistry, andMicrosoft.Authorizationresource providers registered - Minimum 6 vCPUs quota in your target region (3 x Standard_B2s nodes)
Step 1: Build and deploy infrastructure
Section titled “Step 1: Build and deploy infrastructure”“Build the ARM template for the AKS microservice example and deploy it.”
cd examples/k8s-aks-microservice
# Set the resource group nameexport AZURE_RESOURCE_GROUP=aks-microservice-rg
# Create the resource groupaz group create --name $AZURE_RESOURCE_GROUP --location eastus
# Build both ARM template and K8s manifestsnpm run build
# Deploy the ARM templatenpm run deploy-infraThe deployment creates the VNet, AKS cluster, container registry, managed identities with role assignments, and a DNS zone. AKS cluster creation takes ~5-10 minutes.
Step 2: Configure kubectl and load outputs
Section titled “Step 2: Configure kubectl and load outputs”“Configure kubectl for the AKS cluster and load the deployment outputs into .env.”
# Update kubeconfignpm run configure-kubectlkubectl get nodes # verify — should show 3 nodes
# Write real client IDs from ARM outputs into .envnpm run load-outputsThe load-outputs target queries the ARM deployment, extracts managed identity client IDs, the tenant ID, and the cluster name, and writes them to .env. Bun auto-loads .env at runtime, so the next K8s build uses real values instead of placeholders.
Step 3: Deploy Kubernetes workloads
Section titled “Step 3: Deploy Kubernetes workloads”“Rebuild the K8s manifests with real client IDs and deploy them.”
# Rebuild K8s manifests with real client IDs from .envnpm run build:k8s
# Validate against the live cluster (optional)npm run validate
# Apply all K8s resourcesnpm run apply
# Wait for the app deployment to roll outnpm run waitThe K8s output includes ~20 resources across 5 files: namespace with quotas, autoscaled app deployment, AGIC ingress with ExternalDNS, Azure Disk storage class, and Azure Monitor collector.
Step 4: Verify
Section titled “Step 4: Verify”“Check that everything is running.”
# Quick status checknpm run status
# Application pods (should show 2+ Running)kubectl get pods -n microservice
# Ingress (Application Gateway address appears after 2-3 min)kubectl get ingress -n microservice
# Observability agentskubectl get daemonsets -A
# Test the endpoint (once DNS propagates)GATEWAY_IP=$(kubectl get ingress -n microservice microservice-agic -o jsonpath='{.status.loadBalancer.ingress[0].ip}')curl -s -o /dev/null -w "%{http_code}" http://$GATEWAY_IP/Gotchas
Section titled “Gotchas”- Application Gateway takes 2-3 minutes to configure after
kubectl apply. Checkkubectl describe ingressfor events if it’s slow. - Delete order matters — always delete K8s resources before the resource group. If you delete the resource group first, AGIC can’t clean up the Application Gateway backend configuration.
- AKS ships metrics-server — HPA works out of the box. Do not deploy a separate MetricsServer composite.
- Workload Identity requires federated credentials — the managed identity must have a federated credential configured for the AKS OIDC issuer and the specific service account.
Subsequent deployments
Section titled “Subsequent deployments”- K8s-only changes (app config, scaling, new workloads): edit source, run
npm run build:k8s && npm run apply. No infra redeploy needed. - Infrastructure changes (node count, new identities, new role assignments): edit source, run
npm run build && npm run deploy-infra. Then runnpm run load-outputsif outputs changed, followed bynpm run build:k8s && npm run apply.
Clean up
Section titled “Clean up”npm run teardownThis runs: kubectl delete → 30s drain wait → az group delete --no-wait.
Further reading
Section titled “Further reading”- Kubernetes lexicon — resource reference, composites, examples
- AKS Composites — AksWorkloadIdentityServiceAccount, AgicIngress, and more
- Azure ARM lexicon — resource reference, composites, examples
- Deploying to AKS — Azure lexicon bridge page
- Agent Integration guide — using chant skills with Claude Code