Ich habe eine App mit einem einzigen Befehl auf Azure Kubernetes Service deployt: kubectl apply. Eine Sekunde später kam: created. Die erste echte Antwort meiner App kam 34 Sekunden danach.
Dieser Explainer verfolgt genau dieses eine Deployment Sekunde für Sekunde: was „created“ wirklich verspricht, warum ein Pod mit dem Status Running noch keinen Traffic bekommt, wo AKS die öffentliche IP anlegt und warum ein bereiter Pod trotzdem nicht sofort erreichbar ist. Alles unten stammt aus einem echten Lauf auf meinem eigenen AKS-Cluster. Das Video ist auf Englisch.
Das Wichtigste
- Created heißt gespeichert.
kubectl applykehrt zurück, sobald der API-Server Ihr Manifest geprüft und als gewünschten Zustand gespeichert hat. Die eigentliche Arbeit erledigen danach Controller, Scheduler und Kubelet. - Running ist nicht ready. Ein Pod mit dem Status Running hat einen gestarteten Container. Der Service schickt Traffic nur an Pods, deren Readiness-Probe erfolgreich war (READY 1/1). In meinem Lauf: Running nach etwa 4 Sekunden, ready nach 25.
- Die öffentliche IP liegt in einer Ressourcengruppe, die Sie nicht angelegt haben. Ein Service vom Typ
LoadBalancerlässt AKS eine öffentliche IP am Azure Load Balancer des Clusters anlegen, beides in der Node-RessourcengruppeMC_<Ressourcengruppe>_<Cluster>_<Region>, die AKS gehört und mit dem Cluster gelöscht wird. - Ready ist nicht erreichbar. Der Azure Load Balancer prüft jeden Node auf dem Node-Port des Service, standardmäßig alle fünf Sekunden, und leitet erst weiter, wenn diese Prüfung besteht. In meinem Lauf kam die erste Antwort von außen neun Sekunden, nachdem der Pod bereit war.
Was created bedeutet
kubectl schickt Ihr YAML an den API-Server des Clusters, die Rezeption von Kubernetes. Der API-Server prüft die Objekte, speichert sie als gewünschten Zustand und antwortet sofort. Diese Antwort ist das Wort „created“:
> kubectl apply -f k8s/deployment.apps/aks-api createdservice/aks-api-service created
Etwa eine Sekunde, und noch lief nichts. Dann übernehmen Controller: kleine Schleifen, die vergleichen, was Sie angefordert haben, mit dem, was existiert, und die Differenz beheben. Der Controller des Deployments legt ein ReplicaSet an, dessen einzige Aufgabe es ist, die richtige Anzahl Pods laufen zu lassen. Ein Pod ist die Hülle um Ihren Container; das ReplicaSet legt ihn an. Der Scheduler wählt einen Node für den Pod (eine der virtuellen Maschinen des Clusters), und das Kubelet, der Agent auf diesem Node, zieht das Image aus Ihrer Registry und startet den Container. Jeder Name baut auf dem vorherigen auf:
> 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 ist der Bon an der Schiene, nicht der Teller auf dem Tisch.
Running und ready
Direkt nach dem Apply habe ich einen kleinen Watcher gestartet, der nur Änderungen ausgibt. Nach etwa vier Sekunden zeigte der Pod Running 0/1: Der Container war gestartet. Der Service schickte ihm aber noch keinen Traffic, denn ready ist eine eigene Prüfung.
Das Deployment-Manifest des Learn-Moduls enthält eine Readiness-Probe:
readinessProbe:httpGet:path: /readyzport: http # the container port named http = 8000initialDelaySeconds: 15periodSeconds: 10
Das Kubelet ruft die App auf /readyz auf. Zwei Zahlen bestimmen den Zeitpunkt: wie lange die Probe vor dem ersten Aufruf wartet (initialDelaySeconds) und wie oft sie danach aufruft (periodSeconds). Solange kein Aufruf erfolgreich ist, ist der Pod nicht bereit, und die Liste der Endpoints des Service (die Pods, an die er Traffic schicken darf) bleibt leer. In meinem Lauf hatte er bis 25 Sekunden null bereite Endpoints, dann einen.
Running heißt, der Prozess ist gestartet. Ready heißt, die Probe hat ja gesagt. Nur bereite Pods bekommen Traffic.
Die öffentliche IP
Der Service im Manifest hat den Typ LoadBalancer:
spec:type: LoadBalancerselector:app: aks-apiversion: v1ports:- port: 80targetPort: http
Für diesen Typ fordert AKS bei Azure eine öffentliche IP am Load Balancer des Clusters an und richtet sie auf den Service. Die externe IP stand etwa sechzehn Sekunden auf <pending>:
> 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
Ich hatte für diesen Cluster genau eine Ressourcengruppe angelegt. Dort liegt die IP nicht. Sie liegt in der Node-Ressourcengruppe des Clusters, die AKS neben meiner angelegt hat:
> 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
Zwei öffentliche IPs (eine für meinen Service, eine für den ausgehenden Traffic des Clusters), der Load Balancer, das Scale Set hinter meinem Node, ein Netzwerk, eine Sicherheitsgruppe und eine Identität. AKS löscht diese Gruppe mit dem Cluster; ändern Sie dort nichts von Hand.
Der Weg hinein: Clients rufen Port 80 auf der öffentlichen IP auf. Der Load Balancer gibt den Aufruf an den Node weiter, auf einem Node-Port, den der Service dort geöffnet hat (31652 in 80:31652/TCP). Der Service reicht ihn an den Port http des Pods weiter, 8000.
Ready und erreichbar
Zwischen sechzehn Sekunden (die IP existierte) und fünfundzwanzig (der Pod war bereit) bekam ein Aufruf von außen gar nichts: keinen Fehler, nur ein Timeout. Und auch nachdem der Pod bereit war, dauerte es noch neun Sekunden:
> 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
Der Grund sitzt vor dem Cluster. Der Azure Load Balancer prüft jeden Node auf dem Node-Port des Service, standardmäßig alle fünf Sekunden. Solange hinter diesem Port kein bereiter Pod sitzt, schlägt die Prüfung fehl, und der Load Balancer schickt nichts an den Node. Auch nachdem der Pod bereit ist, muss der Load Balancer die Prüfung erst bestehen sehen.
Es gibt also drei Zeitpunkte: created (1 s), ready (25 s) und erreichbar (34 s). Nur der letzte beantwortet Ihre Nutzer.
Die fünfzehn Sekunden in meinem eigenen Manifest
Das Manifest, das ich deployt habe, stammte direkt aus dem Modul. Seine Readiness-Probe wartet fünfzehn Sekunden, und das Kubelet ruft nur im Zehn-Sekunden-Takt auf, also kam der erste Aufruf nach fünfundzwanzig. Meine kleine App braucht so lange nicht. Ich habe dieselbe App noch einmal mit initialDelaySeconds: 1 deployt:
> 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
Bereit nach elf Sekunden statt fünfundzwanzig, die erste Antwort nach achtzehn statt vierunddreißig. Setzen Sie diese Verzögerung auf das, was Ihre App wirklich braucht, nicht auf eine kopierte Zahl. Braucht eine App wirklich lange zum Starten, ist eine Startup-Probe das sauberere Werkzeug als eine lange Anfangsverzögerung.
Was in meinem Lauf passiert ist
Getestet am 26. Oktober 2026 in meinem eigenen Azure-Abonnement (AKS 1.36 in westeurope, Azure CLI 2.88.0, kubectl 1.36); danach wurde alles gelöscht. Der Cluster hatte einen Node Standard_D2s_v5, den Free-Tarif und die Registry per --attach-acr angebunden, wie in der Übung des Moduls. Die App ist eine kleine Python-API nach dem Vorbild der Übung (Port 8000, /healthz, /readyz); die App der Übung ruft zusätzlich ein Modell in Microsoft Foundry auf, das dieser Lauf weggelassen hat.
- Mein erster Versuch, den Cluster in Germany West Central anzulegen, schlug fehl:
(AKSCapacityHeavyUsage) Creating a new cluster is unavailable at this time in region germanywestcentral.In West Europe klappte es; der Cluster brauchte 3 min 54 s. kubectl eventserzählte dieselbe Geschichte aus Sicht des Clusters: Scheduled und Pulling direkt nach dem Apply, das Image gezogen und der Container gestartet etwa vier Sekunden später, undEnsuredLoadBalanceretwa sechzehn Sekunden nachEnsuringLoadBalancer.- Der Load Balancer hatte eine Regel für den Service, nach ihm benannt:
<hash>-TCP-80. - Die Uhr des Watchers startet etwa eine halbe Sekunde, nachdem Apply zurückkam; im Video sind die Zahlen deshalb gerundet.
Was das Video weglässt
- Requests und Limits, die anderen Service-Typen (ClusterIP, NodePort) und Pod-Zustände, die nie starten (ImagePullBackOff, CrashLoopBackOff): Diese Themen bekommen eigene Videos in dieser Reihe.
- Die Liveness-Probe: Das Video zu Health Probes bei Container Apps erklärt Liveness und Readiness.
externalTrafficPolicy: Localund den Shared-Health-Probe-Modus des AKS Load Balancers (Preview): Beides ändert, wie der Load Balancer Nodes prüft.





