Background
Sections
IntroductionFoundations1. Resource Hierarchy2. Resource Manager3. Identity and RBAC4. Regions and Availability5. Naming and TaggingVirtual Machines1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetVirtual Network1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetBlob Storage1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure SQL Database1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Kubernetes Service1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Container Registry1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetMicrosoft Entra ID1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure RBAC1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Functions1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAPI Management1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure App Configuration1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Machine Learning1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure Monitor1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and CheatsheetAzure AI Foundry1. What and Why2. Core Concepts3. Architecture4. Getting Started5. Deployment6. Integrations7. Production8. Interview Questions9. Glossary and Cheatsheet

4. Getting Started

6 min read

The smallest thing that proves a cluster works: create it, deploy one container, reach it from the internet, delete everything. Three ways, because interviews and real jobs use all three.

This page is deliberately throwaway. Hard-coded names, a public API server, one node pool, no variables, no state backend, no pipeline. It exists to build intuition and be deleted twenty minutes later. Everything production-shaped — modules, remote state, private clusters, OIDC pipelines, rollback — lives in Deployment. If a snippet here would embarrass you in a pull request, that's the point.

Before you start

az login
az account set --subscription "<your-subscription>"
az account show -o table

# kubectl and the Entra credential plugin, installed into your PATH
az aks install-cli

Two things to check first, because both bite beginners:

  • vCPU quota. A cluster needs enough of the VM family you pick in that region. az vm list-usage -l uksouth -o table and look for the family you're about to use — a QuotaExceeded failure halfway through cluster creation is the most common first experience of AKS.
  • Region. Pick one close to you that has availability zones. Everything below uses uksouth; substitute freely.

The task

One AKS cluster with a single small node pool → deploy an NGINX pod → expose it with a LoadBalancer Service → hit it in a browser → delete the resource group.

1. Azure Portal

Short click-path; the portal's navigation changes often, so this describes destinations rather than exact button labels.

  • Create a resource → Kubernetes service, then choose the cluster preset — pick Dev/Test for this exercise so it doesn't provision a production-sized cluster.
  • On Basics, create a new resource group rg-aks-demo, name the cluster aks-demo, choose your region, leave the Kubernetes version at default, and set the pricing tier to Free (it's a demo; in production this is Standard).
  • On Node pools, reduce the default system pool to 1 node of a small burstable or general size, and leave autoscaling off.
  • Skip Networking, Integrations, and Monitoring — the defaults are fine for a throwaway, and Container Insights on a demo cluster generates a small bill for logs nobody reads.
  • Review + create. Provisioning takes several minutes; the portal's Connect button on the cluster blade gives you the az aks get-credentials line for the next step.

Note what the portal just did that it didn't tell you: it created a second resource group named MC_rg-aks-demo_aks-demo_uksouth holding the scale set, the disks, and the load balancer.

2. Azure CLI

The whole exercise, copy-pasteable.

# --- Create ---------------------------------------------------------------
az group create -n rg-aks-demo -l uksouth

az aks create \
  -g rg-aks-demo \
  -n aks-demo \
  --tier free \
  --node-count 1 \
  --node-vm-size Standard_B2s \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --enable-managed-identity \
  --generate-ssh-keys

# --- Connect --------------------------------------------------------------
az aks get-credentials -g rg-aks-demo -n aks-demo
kubectl get nodes -o wide

# --- Deploy ---------------------------------------------------------------
kubectl create deployment hello --image=mcr.microsoft.com/cbl-mariner/base/nginx:1.22
kubectl expose deployment hello --type=LoadBalancer --port=80 --target-port=80

# --- Watch Azure provision a load balancer on your behalf -----------------
kubectl get service hello --watch     # EXTERNAL-IP moves from <pending> to an IP

When EXTERNAL-IP appears, curl it. That IP is an Azure public IP resource that was created in the node resource group by the cloud controller manager because you asked Kubernetes for a LoadBalancer Service. Look at it:

NODE_RG=$(az aks show -g rg-aks-demo -n aks-demo --query nodeResourceGroup -o tsv)
az resource list -g "$NODE_RG" -o table

That listing — a scale set, a disk, a load balancer, a public IP, an NSG — is the single most useful five seconds in this page. Your Kubernetes objects create Azure resources.

A few commands worth running while it's alive:

kubectl get pods -o wide                     # which node did it land on?
kubectl describe pod -l app=hello            # events are where failures explain themselves
kubectl logs -l app=hello
kubectl get events --sort-by=.lastTimestamp  # the cluster's own narration
az aks show -g rg-aks-demo -n aks-demo --query "{version:kubernetesVersion, tier:sku.tier, rg:nodeResourceGroup}" -o yaml

PowerShell equivalent

Included here because AKS clusters are commonly created from Windows admin workstations and by Azure-DevOps-centric shops:

New-AzResourceGroup -Name rg-aks-demo -Location uksouth
New-AzAksCluster -ResourceGroupName rg-aks-demo -Name aks-demo -NodeCount 1 -NodeVmSize Standard_B2s
Import-AzAksCredential -ResourceGroupName rg-aks-demo -Name aks-demo

3. Terraform — minimal

Hello-world only: one file, hard-coded, no variables, no backend. The parameterised module is in Deployment.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "demo" {
  name     = "rg-aks-demo"
  location = "uksouth"
}

resource "azurerm_kubernetes_cluster" "demo" {
  name                = "aks-demo"
  location            = azurerm_resource_group.demo.location
  resource_group_name = azurerm_resource_group.demo.name
  dns_prefix          = "aksdemo"
  sku_tier            = "Free"

  default_node_pool {
    name       = "system"     # 1-12 lowercase alphanumeric characters, must start with a letter
    node_count = 1
    vm_size    = "Standard_B2s"
  }

  identity {
    type = "SystemAssigned"
  }

  network_profile {
    network_plugin      = "azure"
    network_plugin_mode = "overlay"
  }
}

output "kube_config_command" {
  value = "az aks get-credentials -g ${azurerm_resource_group.demo.name} -n ${azurerm_kubernetes_cluster.demo.name}"
}
terraform init
terraform plan
terraform apply

Two things to notice in the plan output, both of which matter later:

  • The node resource group is not in your Terraform state. Terraform created one resource; Azure created a dozen. Terraform will never manage those, and that asymmetry is the root of several deployment-time surprises.
  • The default_node_pool block is inside the cluster resource. Additional pools are separate azurerm_kubernetes_cluster_node_pool resources — the first pool is special, and changing its vm_size is the change that historically forced the whole cluster to be replaced.

[Image Prompt: 2D minimalistic diagram comparing three provisioning paths — Azure Portal, az CLI, and Terraform — all converging on the same AKS cluster resource which in turn creates a node resource group, flat design, clean vector art style, white background]

Teardown

Do this now, not later. An idle single-node demo cluster still bills for the node VM, its disk, the load balancer, and the public IP.

# Terraform path
terraform destroy

# CLI path — one command removes the cluster AND its node resource group
az group delete -n rg-aks-demo --yes --no-wait

Deleting the resource group is the cleanest teardown Azure offers and it's a genuine advantage over AWS: because every resource lives in exactly one resource group, one delete removes the cluster, the node resource group, the scale set, the disks, the load balancer, and the public IP. Two things it will not remove: anything you created in a different resource group (an ACR, a Key Vault), and anything protected by a resource lock or soft delete.

Verify:

az group list --query "[?starts_with(name,'rg-aks-demo') || starts_with(name,'MC_rg-aks-demo')].name" -o tsv

Empty output means you're done.

What you should be able to do now

Create a cluster three ways, get credentials, deploy a container, expose it, and — most importantly — point at the node resource group and explain that the Kubernetes objects you typed became Azure resources you're being billed for.


Next: Deployment →

← Back to the Azure Kubernetes Service overview · ← Previous: Architecture