I deployed an app to Azure Kubernetes Service with one command, kubectl apply. One second later it said: created. The first real answer from my app came thirty-four seconds after that.
This explainer follows that one deploy second by second: what "created" really promises, why a pod that says Running gets no traffic yet, where AKS puts the public IP, and why a ready pod still isn't reachable right away. Everything below comes from a real run on my own AKS cluster.
Key points
- Created means stored.
kubectl applyreturns as soon as the API server has checked your manifest and stored it as the desired state. Controllers, the scheduler and the kubelet do the actual work afterwards. - Running is not ready. A pod that says Running has a started container. The Service only sends traffic to pods whose readiness probe has succeeded (READY 1/1). In my run: Running at about 4 seconds, ready at 25.
- The public IP lives in a resource group you didn't create. A Service of type
LoadBalancermakes AKS add a public IP to the cluster's Azure load balancer, both in the node resource groupMC_<resource group>_<cluster>_<region>, which AKS owns and deletes with the cluster. - Ready is not reachable. The Azure load balancer checks each node on the Service's node port, every five seconds by default, and only forwards traffic once that check passes. In my run, the first answer from outside came nine seconds after the pod was ready.
What created means
kubectl sends your YAML to the cluster's API server, the front desk of Kubernetes. The API server checks the objects, stores them as the desired state and answers right away. That answer is the word "created":
> kubectl apply -f k8s/deployment.apps/aks-api createdservice/aks-api-service created
About one second, and nothing was running yet. Then controllers take over: small loops that compare what you asked for with what exists and fix the difference. The Deployment's controller creates a ReplicaSet, whose only job is to keep the right number of pods running. A pod is the wrapper around your container; the ReplicaSet creates it. The scheduler picks a node for the pod (one of the cluster's virtual machines), and the kubelet, the agent on that node, pulls the image from your registry and starts the container. Each name builds on the one before:
> kubectl get deploy,rs,pods -l app=aks-apiNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/aks-api 1/1 1 1 35sNAME DESIRED CURRENT READY AGEreplicaset.apps/aks-api-74ffd6567d 1 1 1 36sNAME READY STATUS RESTARTS AGEpod/aks-api-74ffd6567d-6lht7 1/1 Running 0 36s
Created is the ticket on the rail, not the plate on the table.
Running and ready
Right after the apply I started a small watcher that prints only what changes. At about four seconds the pod said Running 0/1: the container had started. But the Service didn't send it any traffic yet, because ready is a separate check.
The Learn module's deployment manifest has a readiness probe:
readinessProbe:httpGet:path: /readyzport: http # the container port named http = 8000initialDelaySeconds: 15periodSeconds: 10
The kubelet calls the app on /readyz. Two numbers decide when: how long the probe waits before its first call (initialDelaySeconds) and how often it calls after that (periodSeconds). Until a call succeeds, the pod isn't ready, and the Service's list of endpoints (the pods it may send traffic to) stays empty. In my run it had zero ready endpoints until 25 seconds, then one.
Running means the process started. Ready means the probe said yes. Only ready pods get traffic.
The public IP
The Service in the manifest has the type LoadBalancer:
spec:type: LoadBalancerselector:app: aks-apiversion: v1ports:- port: 80targetPort: http
For that type, AKS asks Azure for a public IP on the cluster's load balancer and points it at the Service. The external IP said <pending> for about sixteen seconds:
> kubectl get svc aks-api-serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEaks-api-service LoadBalancer 10.0.88.69 203.0.113.10 80:31652/TCP 36s
I created one resource group for this cluster. The IP isn't in it. It sits in the cluster's node resource group, which AKS created next to mine:
> az aks show -g rg-demo -n aks-demo --query nodeResourceGroup -o tsvMC_rg-demo_aks-demo_westeurope> az resource list -g MC_rg-demo_aks-demo_westeurope --query "[].type" -o tsvMicrosoft.Network/publicIPAddressesMicrosoft.Network/loadBalancersMicrosoft.ManagedIdentity/userAssignedIdentitiesMicrosoft.Network/networkSecurityGroupsMicrosoft.Network/virtualNetworksMicrosoft.Compute/virtualMachineScaleSetsMicrosoft.Network/publicIPAddresses
Two public IPs (one for my Service, one for the cluster's outgoing traffic), the load balancer, the scale set behind my node, a network, a security group and an identity. AKS deletes this group with the cluster; don't change things there by hand.
The way in: clients call port 80 on the public IP. The load balancer hands the call to the node, on a node port the Service opened there (31652 in 80:31652/TCP). The Service passes it on to the pod's port named http, 8000.
Ready and reachable
Between sixteen seconds (the IP existed) and twenty-five (the pod was ready), a call from outside got nothing at all: no error, just a timeout. And even after the pod was ready, it took another nine seconds:
> python watch.py up aks-api --secs 300...15.8s svc aks-api-service EXTERNAL-IP 203.0.113.1018.1s GET http://203.0.113.10/ timed out25.0s svc aks-api-service ready endpoints 134.4s GET http://203.0.113.10/ 200 aks-api-74ffd6567d-6lht7
The reason sits in front of the cluster. The Azure load balancer checks every node on the Service's node port, every five seconds by default. As long as no ready pod sits behind that port, the check fails and the load balancer sends nothing to the node. After the pod is ready, the load balancer still has to see the check pass.
So there are three moments: created (1 s), ready (25 s) and reachable (34 s). Only the last one answers your users.
The fifteen seconds in my own manifest
The manifest I deployed came straight from the module. Its readiness probe waits fifteen seconds, and the kubelet only calls on a ten-second beat, so the first call landed at twenty-five. My little app doesn't need that long. I deployed the same app again with initialDelaySeconds: 1:
> python watch.py up aks-api-fast --secs 300...11.0s aks-api-fast-7f69b58c5-4jwsz Running 1/114.9s svc aks-api-fast-service EXTERNAL-IP 203.0.113.1118.1s GET http://203.0.113.11/ 200 aks-api-fast-7f69b58c5-4jwsz
Ready at eleven seconds instead of twenty-five, the first answer at eighteen instead of thirty-four. Set that delay to what your app really needs, not to a number you copied. If an app really needs long to start, a startup probe is the cleaner tool than a long initial delay.
What happened when I ran it
Tested on October 26, 2026 in my own Azure subscription (AKS 1.36 in westeurope, Azure CLI 2.88.0, kubectl 1.36); everything was deleted afterwards. The cluster had one Standard_D2s_v5 node, the free tier and the registry attached with --attach-acr, as in the module's exercise. The app is a small Python API shaped like the exercise's (port 8000, /healthz, /readyz); the exercise's app also calls a model in Microsoft Foundry, which this run left out.
- My first try to create the cluster in Germany West Central failed:
(AKSCapacityHeavyUsage) Creating a new cluster is unavailable at this time in region germanywestcentral.West Europe worked; the cluster took 3 min 54 s. kubectl eventstold the same story from the cluster's side: Scheduled and Pulling right after the apply, the image pulled and the container started about four seconds later, andEnsuredLoadBalancerabout sixteen seconds afterEnsuringLoadBalancer.- The load balancer had one rule for the Service, named after it:
<hash>-TCP-80. - The watcher's clock starts about half a second after the apply returned, so the numbers above are rounded in the video.
What the video leaves out
- Requests and limits, the other Service types (ClusterIP, NodePort) and the pod states that never start (ImagePullBackOff, CrashLoopBackOff): those get their own videos in this series.
- The liveness probe: the Container Apps video on health probes explains liveness vs readiness.
externalTrafficPolicy: Localand the shared health probe mode of the AKS load balancer (preview): both change how the load balancer checks nodes.





