Creating an AKS Cluster
Why this matters
Everything else in this track happens on top of a real cluster. This
module is where you turn az commands into an actual running set of VMs
in Azure, and where the "this costs real money while it's running" reality
of the AKS track starts. Getting the initial az aks create right — small
node pool, right tier, right identity — saves you from surprises later.
Concepts
Node pools. In kind/minikube, "nodes" were containers or a single VM faking a cluster. In AKS, a node pool is a group of real Azure VMs (of a size/SKU you choose) that all run the same OS image and join the cluster as Kubernetes nodes. Every AKS cluster has at least one system node pool, which runs critical cluster add-ons (CoreDNS, metrics-server, etc.) alongside your workloads. You can add additional user node pools later for workload isolation (e.g. a pool with GPU VMs) — not needed yet.
VM size (SKU). Each node pool picks one VM size for all its nodes,
e.g. Standard_B2s (burstable, cheap, fine for learning) or
Standard_D2s_v5 (steadier general-purpose). Bigger/faster VMs cost more
per hour whether or not you use the capacity — for this track, pick the
smallest size that can actually run the exercises (2 vCPU / a few GB RAM
class is enough).
Node count. How many VMs are in the pool. AKS needs a minimum of one, but a single-node cluster can't demonstrate rescheduling behavior when a node fails, so this track uses two nodes for its learning cluster.
Cluster tiers: Free vs. Standard. This controls the control plane's SLA and scale limits, not the nodes. Free tier has no uptime SLA (fine for learning — Azure's control plane is still reliable in practice, just not contractually guaranteed) and is what this track uses throughout. Standard tier adds an availability SLA and is meant for production clusters; it has an hourly cost for the control plane itself, on top of node costs. Don't pick Standard for a learning cluster you plan to delete the same day.
What AKS manages vs. what you own, concretely, at cluster-creation
time: Azure manages the control plane's placement, availability, and
patching. You are responsible for: the node pool's VM size and count
(and therefore its cost), the Kubernetes version you run (Azure offers
supported versions; you choose and later upgrade), and the resource group
and network the cluster lives in. Unlike kind/minikube, tearing a cluster
down here is not "stop a local process" — it's deleting real
infrastructure, hence az group delete.
az aks get-credentials downloads a kubeconfig context for the
cluster and merges it into your local ~/.kube/config, the same file
kubectl already reads for your kind/minikube contexts. After this,
kubectl config get-contexts shows your AKS cluster alongside any local
ones, and kubectl config use-context (or --context) switches between
them — a real risk if you have both a local and AKS context and run a
command assuming the wrong one is active.
Command reference
| Command | What it does | Example |
|---|---|---|
az aks create |
Creates a new AKS cluster in a resource group | az aks create --resource-group rg-aks-learn --name aks-learn --node-count 2 --node-vm-size Standard_B2s --tier free --generate-ssh-keys |
--node-count |
Number of nodes in the initial (system) node pool | --node-count 2 |
--node-vm-size |
VM size/SKU for the node pool | --node-vm-size Standard_B2s |
--tier |
Control plane tier: free or standard |
--tier free |
--generate-ssh-keys |
Auto-generates an SSH key pair if you don't already have one, required for node VM provisioning | --generate-ssh-keys |
--kubernetes-version |
Pins a specific supported Kubernetes version instead of the current default | --kubernetes-version 1.29.7 |
az aks get-credentials |
Downloads/merges kubeconfig for a cluster into ~/.kube/config |
az aks get-credentials --resource-group rg-aks-learn --name aks-learn |
az aks list |
Lists AKS clusters in the current subscription | az aks list --output table |
az aks show |
Shows details of one cluster | az aks show --resource-group rg-aks-learn --name aks-learn --output table |
az aks nodepool list |
Lists node pools in a cluster | az aks nodepool list --resource-group rg-aks-learn --cluster-name aks-learn --output table |
az aks scale |
Changes the node count of a node pool | az aks scale --resource-group rg-aks-learn --name aks-learn --node-count 1 --nodepool-name nodepool1 |
az aks stop |
Stops the cluster's control plane and nodes (billing pauses for nodes, not for some other resources like disks/IPs) | az aks stop --resource-group rg-aks-learn --name aks-learn |
az aks start |
Restarts a stopped cluster | az aks start --resource-group rg-aks-learn --name aks-learn |
kubectl config get-contexts |
Lists kubeconfig contexts (local + AKS) | kubectl config get-contexts |
kubectl config use-context |
Switches the active kubeconfig context | kubectl config use-context aks-learn |
kubectl get nodes |
Lists nodes the cluster's API server sees | kubectl get nodes -o wide |
az group delete |
Deletes the resource group (and cluster) entirely | az group delete --name rg-aks-learn --yes --no-wait |
Hands-on exercises
Recreate the resource group if needed. If you deleted
rg-aks-learnat the end of module 00, recreate it:az group create --name rg-aks-learn --location eastus.Create a small learning cluster. Run:
az aks create \ --resource-group rg-aks-learn \ --name aks-learn \ --node-count 2 \ --node-vm-size Standard_B2s \ --tier free \ --generate-ssh-keysThis takes several minutes. Verify: the command eventually prints JSON with
"provisioningState": "Succeeded"and"powerState": {"code": "Running"}.Look at what got created. Run
az aks show --resource-group rg-aks-learn --name aks-learn --output tableand note the Kubernetes version and tier. Then runaz group list --output table— notice a second, AKS-managed resource group now exists named something likeMC_rg-aks-learn_aks-learn_eastus. This is where the actual node VMs, disks, NICs, and (later) load balancers live — don't delete it directly; it's tied to the cluster's lifecycle and gets cleaned up when the cluster is deleted.Wire up
kubectl. Runaz aks get-credentials --resource-group rg-aks-learn --name aks-learn. Verify withkubectl config get-contexts— you should see an entry foraks-learn(marked*as current if it just got set active alongside any existing kind/minikube contexts).Verify the nodes. Run
kubectl get nodes -o wide. Verify: two nodes listed,STATUS=Ready, and theKUBELET-VERSIONmatching whataz aks showreported. Also trykubectl get nodes -o wide --context aks-learnexplicitly, and compare against a local context if you still have one (kubectl config get-contexts) to build the habit of checking which cluster you're pointed at.Inspect a node pool. Run
az aks nodepool list --resource-group rg-aks-learn --cluster-name aks-learn --output table. Verify: one pool (commonly namednodepool1),COUNT= 2,VMSIZEmatching what you requested.Diagnose and fix: nodes not ready. Simulate/observe a "nodes not ready" investigation even without breaking anything: run
kubectl describe node <one-of-your-node-names>and read theConditionssection (Ready,MemoryPressure,DiskPressure,PIDPressure,NetworkUnavailableshould all be healthy/FalseexceptReady=True). Now deliberately scale to a size that could strain aStandard_B2snode: skip actually deploying anything huge, but note down what you'd check if a node showedReady=False— runkubectl get events --sort-by=.lastTimestampandkubectl describe node <name>and look at theEventssection for causes like disk pressure, kubelet not posting status, or a failed VM extension. (You'll cause an actual resource-pressure failure on purpose in module 02's diagnose exercise.)Try stop/start (optional, cost-saving). If you want to pause billing on node VMs without deleting the cluster between study sessions, run
az aks stop --resource-group rg-aks-learn --name aks-learn, wait for it to complete, thenaz aks start --resource-group rg-aks-learn --name aks-learnbefore your next session. Verify stop worked withaz aks show --resource-group rg-aks-learn --name aks-learn --query powerState(should showStopped, thenRunningagain after start). Note: stop pauses node VM billing but some resources (disks, reserved public IPs) may still bill while stopped — check the portal if you're unsure.Clean up. If you're done with this cluster for the day and don't need it for module 02 immediately, delete everything:
az group delete --name rg-aks-learn --yes --no-wait. If you're continuing straight into module 02, you may leave the cluster running — just don't forget it's billing while it exists.
Independent challenge
No commands given here — figure it out yourself using what you know from this module and earlier ones.
Task: Provision a learning cluster the cost-conscious way, then investigate one thing the exercises above never make you look at: exactly how much of each small node the system add-ons have already claimed before you deploy anything of your own. Create a minimal two-node cluster in the resource group you set up in module 00 (conceptually building on module 00's resource-group and subscription work), wire kubectl to it, and confirm both nodes are healthy. Then, without deploying any workload, determine how much CPU and memory on each node is already reserved or requested by the cluster's own system components, and form an opinion on how many of your own pods a node this size could realistically hold. Finally, decide whether to pause billing or tear the cluster down for the day, and actually do it — leaving a two-node cluster idle overnight is exactly the charge this track keeps warning you about.
Stuck? One hint
kubectl describe node <name> reports both the node's total capacity and its already-allocated requests near the bottom; compare "Allocatable" against the "Allocated resources" table to see the real headroom.
Common mistakes & troubleshooting
- Picking too large a VM size "to be safe."
Standard_D4s_v5or bigger for a 2-node learning cluster is unnecessary cost for no benefit in this track —Standard_B2s(or similar burstable 2 vCPU size) is enough for every exercise here. - Choosing
--tier standardout of habit. Standard tier adds a control-plane SLA cost meant for production; usefreefor learning clusters you plan to tear down. - Forgetting the
MC_*resource group exists. It's not a mistake to see it, but people sometimes try to manually delete resources inside it, which fights the cluster's own reconciliation. Manage it through the AKS cluster/node pool, not by hand. - Running
kubectlagainst the wrong context after adding AKS. Once you have both local and AKS contexts, always checkkubectl config current-contextbefore running anything you don't want to accidentally point at production-shaped infrastructure. - Cost pitfall: leaving a "just for testing" cluster running for days.
A 2-node
Standard_B2scluster left running unattended for a week adds up. Get in the habit of runningaz aks stopbetween sessions, oraz group deleteif you're done with a module, rather than leaving clusters idle "just in case."
Checkpoint quiz
Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.
- What's the difference between the system node pool and a user node pool?
- What does the
--tierflag control, and why isfreethe right choice for this track? - Where do the actual node VMs, disks, and NICs for your cluster live, resource-group-wise, and why shouldn't you manage that resource group by hand?
- What does
az aks get-credentialsactually do to your local machine? - What's the practical billing difference between
az aks stopandaz group delete? - If
kubectl get nodesshows a node asNotReady, what two commands would you reach for first to investigate?
Show answers
- The system node pool runs critical cluster add-ons (CoreDNS, metrics-server, etc.) and can also run your workloads; a user node pool is an additional pool you add later, typically to isolate specific workloads (different VM size, GPU, taints, etc.) from the system pool.
--tiercontrols the control plane's SLA/scale tier.freehas no uptime SLA but no extra control-plane cost, which is appropriate for a learning cluster you don't need contractual uptime guarantees for.- In a separate, AKS-managed resource group (named like
MC_<rg>_<cluster>_<region>). You shouldn't manage it by hand because AKS reconciles its contents to match the cluster/node pool state — manual changes there can be overwritten or cause drift; manage node pools throughaz aks/kubectlinstead. - It fetches the cluster's kubeconfig (API server address, cluster CA,
auth info) and merges it as a new context into your local
~/.kube/config, the same file used for local kind/minikube contexts. az aks stoppauses billing on the node VMs (and the cluster is fully deleted-and-recreatable viastart), but some attached resources may still bill.az group deletedeletes the cluster and its resource group entirely — no way to "start" it back; you'd recreate from scratch.kubectl describe node <name>(check theConditionsandEventssections) andkubectl get events --sort-by=.lastTimestamp(see cluster-wide recent events for context).
Next
02-deploying-workloads-to-aks — deploy real workloads to your AKS cluster and see what's different from kind/minikube.