ContainerCreating blijft hangen: pods debuggen die niet starten

ContainerCreating betekent dat de kubelet bezig is met de voorbereidingen van je pod (volumes, netwerk, secrets), maar dat iets het proces blokkeert. Anders dan bij CrashLoopBackOff start de container nooit daadwerkelijk. De oplossing hangt af van welke stap vastloopt: een PVC die niet gebonden raakt, een ontbrekend Secret, een kapotte CNI-plugin, of een init container die niet afrondt. Dit artikel loopt elke oorzaak langs, hoe je die herkent in kubectl-events en hoe je het oplost.

Wat ContainerCreating precies betekent

ContainerCreating is een door de kubelet gerapporteerde wachtstatus, geen officiële Kubernetes-podfase. De werkelijke podfase is Pending. Wat de status je vertelt: de pod is toegewezen aan een node en de kubelet werkt aan de voorbereidende stappen voordat het containerproces kan draaien.

Die stappen zijn:

  • Container-image pullen (als het nog niet gecached is op de node)
  • Podnetwerk-namespace aanmaken via de CNI-plugin
  • PersistentVolumes attachen en mounten
  • ConfigMaps, Secrets en projected volumes injecteren in het containerfilesysteem
  • Init containers tot voltooiing draaien

Als een van deze stappen vastloopt, blijft de pod in ContainerCreating hangen. Er is geen ingebouwde timeout die de pod naar Failed verplaatst. De kubelet blijft het gewoon opnieuw proberen, dus je moet zelf ingrijpen.

Verschil met verwante statussen. ImagePullBackOff betekent dat het image-pullen specifiek is mislukt en de kubelet wacht voor een nieuwe poging. CreateContainerConfigError betekent dat een ConfigMap- of Secret-referentie ongeldig is en Kubernetes dat al bij configuratietijd heeft gedetecteerd. Init:N/M betekent dat init containers nog draaien. Als je ContainerCreating ziet, is het image ofwel al gepulld ofwel nog niet geprobeerd, en ligt het probleem ergens anders.

kubectl describe pod events lezen

De Events-sectie van kubectl describe pod is veruit het nuttigste diagnostische hulpmiddel. Events verlopen standaard na een uur in de API-server, dus bekijk ze op tijd.

kubectl describe pod <pod-name> -n <namespace>

Scroll naar de Events-sectie onderaan. Een gezonde pod toont dit verloop:

Normal   Scheduled      Successfully assigned default/my-pod to node-3
Normal   Pulling        Pulling image "registry.internal/my-app:2.4.1"
Normal   Pulled         Successfully pulled image
Normal   Created        Created container my-app
Normal   Started        Started container my-app

Een pod die vasthangt in ContainerCreating stopt voor Created en toont doorgaans Warning-events. Het eerste Warning-event wijst naar de oorzaak.

Warning-reden Waarschijnlijke oorzaak Sectie in dit artikel
FailedMount Volume kan niet gemount worden Volumemount-fouten
FailedAttachVolume Cloud-disk kan niet geattacht worden Volumemount-fouten
FailedCreatePodSandBox CNI-pluginfout CNI-pluginproblemen
Failed met "secret not found" Ontbrekend Secret Ontbrekende ConfigMaps of Secrets
Failed met "configmap not found" Ontbrekende ConfigMap Ontbrekende ConfigMaps of Secrets

Als er helemaal geen events zijn, heeft de kubelet zelf mogelijk problemen. Bekijk de kubelet-logs op de node waar de pod is ingepland (het Node:-veld in de describe-output toont welke node):

# SSH naar de node, dan:
journalctl -u kubelet --since "15 minutes ago" | grep -i "sandbox\|cni\|volume\|mount"

Voor pod-specifieke events gesorteerd op tijd:

kubectl get events -n <namespace> \
  --field-selector involvedObject.name=<pod-name> \
  --sort-by='.lastTimestamp'

Volumemount-fouten

Volumeproblemen zijn de meest voorkomende oorzaak dat ContainerCreating blijft hangen. Er zijn drie verschillende faalscenario's.

PVC niet gebonden

Een pod die verwijst naar een PersistentVolumeClaim met STATUS: Pending kan niet starten. De kubelet wacht tot het volume beschikbaar is.

kubectl get pvc -n <namespace>
# Zoek naar STATUS = Pending

kubectl describe pvc <pvc-name> -n <namespace>
# Events-sectie toont waarom binding mislukte

Waarom een PVC op Pending blijft staan:

  • Geen matchend PersistentVolume. Het cluster heeft geen PV die past bij de StorageClass, access mode of capaciteit van de PVC. Controleer wat er is: kubectl get pv.
  • StorageClass niet gevonden. De storageClassName in de PVC verwijst naar een niet-bestaande class. Verifieer: kubectl get storageclass.
  • Access mode mismatch. Blockstorage (AWS EBS, GCE Persistent Disk, Azure Disk) ondersteunt meestal alleen ReadWriteOnce. Een PVC die ReadWriteMany aanvraagt, bindt daar niet aan.
  • WaitForFirstConsumer binding mode. StorageClasses met volumeBindingMode: WaitForFirstConsumer stellen provisioning uit tot een pod daadwerkelijk is ingepland. De PVC toont Pending tot de scheduler een node kiest. Dit is verwacht gedrag, geen bug. Als de pod zelf niet schedulable is (apart probleem), blijft de PVC op Pending.

Voor een diepere uitleg van de PV/PVC-lifecycle en bindingsmechanismen, zie Kubernetes PersistentVolumes en PersistentVolumeClaims.

Oplossingen:

  1. Maak handmatig een matchend PV, of controleer of de StorageClass-provisioner-pod draait in kube-system.
  2. Corrigeer de storageClassName naar een bestaande class.
  3. Schakel over naar een access mode die compatibel is met het onderliggende storagetype.
  4. Bij WaitForFirstConsumer, debug eerst het schedulingprobleem (zie Pod blijft in Pending).

Je weet dat het gelukt is als: kubectl get pvc -n <namespace> de status Bound toont en de pod uit ContainerCreating komt.

FailedAttachVolume en Multi-Attach-fouten

De kubelet stuurt een FailedAttachVolume-event als een cloud-disk niet aan de node geattacht kan worden. De meest voorkomende oorzaak: een ReadWriteOnce-volume staat nog geregistreerd als geattacht aan een andere node.

Typisch event:

Warning  FailedAttachVolume  Multi-Attach error for volume "pvc-abc123":
  Volume is already exclusively attached to one node and can't be attached to another

Dit gebeurt nadat een pod naar een nieuwe node is verplaatst (schaalactie, nodefout, rolling update) maar de vorige attachment niet is opgeruimd.

Diagnose:

# Bekijk VolumeAttachment-objecten
kubectl get volumeattachment

# Vind stale attachments voor het volume
kubectl get volumeattachment -o json | \
  jq '.items[] | select(.spec.source.persistentVolumeName=="pvc-abc123") | {name: .metadata.name, node: .spec.nodeName, deletionTimestamp: .metadata.deletionTimestamp}'

Oplossingen:

  1. Als de oude pod nog aan het terminaten is, wacht tot die volledig gestopt is: kubectl get pods -n <namespace> -o wide.
  2. Als er een stale VolumeAttachment-object bestaat voor een node die er niet meer is, verwijder het: kubectl delete volumeattachment <name>.
  3. Gebruik bij Deployments met ReadWriteOnce-volumes strategy.type: Recreate in plaats van RollingUpdate. Rolling updates proberen een nieuwe pod op te starten voordat de oude volledig is gestopt, en dat triggert Multi-Attach op RWO-volumes.
  4. Als je gelijktijdige toegang nodig hebt, schakel over naar RWX-capable storage (NFS, AWS EFS, Azure Files).

Je weet dat het gelukt is als: de FailedAttachVolume-events stoppen en de pod naar Running gaat.

CSI-driver draait niet

Als de CSI-controller of node-plugin pods niet draaien, mislukken alle volumeoperaties.

kubectl get pods -n kube-system | grep csi
kubectl get csidrivers

Als de CSI-node-plugin ontbreekt op de doelnode, herstart de DaemonSet:

kubectl rollout restart daemonset <csi-node-plugin> -n kube-system

Grote volumes met fsGroup

Wanneer spec.securityContext.fsGroup is ingesteld, wijzigt de kubelet recursief de eigenaar van elk bestand in het volume bij het mounten. Bij volumes met miljoenen bestanden kan dat minuten duren en een mount-timeout veroorzaken.

Kubernetes 1.20 introduceerde fsGroupChangePolicy (GA in 1.23). Zet het op OnRootMismatch om recursieve ownership-wijzigingen over te slaan als de rootdirectory al de juiste groep heeft:

spec:
  securityContext:
    fsGroup: 2000
    fsGroupChangePolicy: "OnRootMismatch"

Ontbrekende ConfigMaps of Secrets

Als een pod verwijst naar een ConfigMap of Secret die niet bestaat in dezelfde namespace, hangt het gedrag af van hoe de referentie is gemaakt.

Ontbrekend Secret (volume mount): De pod blijft in ContainerCreating. Events tonen:

Warning  FailedMount  MountVolume.SetUp failed for volume "secrets":
  secret "db-credentials" not found

Ontbrekende ConfigMap (env of envFrom): De pod toont meestal CreateContainerConfigError in kubectl get pods, niet ContainerCreating. Events tonen:

Warning  Failed  Error: configmap "app-config" not found

Het verschil: Kubernetes valideert ConfigMap-referenties bij containerconfiguratie (eerder in het proces), terwijl Secret-volumemounts door de kubelet worden opgelost bij het mounten (iets later).

Diagnose:

# Wat refereert de pod?
kubectl describe pod <pod-name> -n <namespace>
# Bekijk de Volumes, Env en EnvFrom secties

# Bestaat de resource in dezelfde namespace?
kubectl get configmap -n <namespace>
kubectl get secret -n <namespace>

Belangrijke regels: een pod kan alleen ConfigMaps en Secrets refereren in dezelfde namespace. Een referentie naar een specifieke key die niet bestaat in de ConfigMap blokkeert ook de startup, tenzij de referentie optional: true heeft.

Oplossingen:

  1. Maak de ontbrekende resource aan:
kubectl create configmap app-config \
  --from-file=config.yaml -n <namespace>

kubectl create secret generic db-credentials \
  --from-literal=password=changeme-in-production -n <namespace>
  1. Markeer de referentie als optioneel als de config niet strikt noodzakelijk is:
volumes:
- name: config
  configMap:
    name: app-config
    optional: true
  1. Na het aanmaken van de resource, trigger een pod restart. Kubernetes probeert het niet automatisch opnieuw:
kubectl rollout restart deployment <deployment-name> -n <namespace>

Je weet dat het gelukt is als: kubectl describe pod geen FailedMount- of Failed-events meer toont die naar de ontbrekende resource verwijzen, en de pod naar Running gaat.

CNI-pluginproblemen

De CNI (Container Network Interface)-plugin wijst een IP-adres toe en configureert netwerkrouting wanneer de pod-sandbox wordt aangemaakt. Als dat mislukt, kan de sandbox niet opgezet worden en blijft de pod in ContainerCreating.

CNI-fouten herkennen. De describe-output toont:

Warning  FailedCreatePodSandBox  Failed to create pod sandbox: rpc error:
  code = Unknown desc = failed to setup network for sandbox "abc123": ...

CNI-specifieke foutmeldingen variëren per plugin:

  • Calico: plugin type="calico" failed (add): error getting ClusterInformation: Unauthorized betekent dat de calico-node DaemonSet niet draait of RBAC-problemen heeft.
  • AWS VPC CNI: failed to assign an IP address to container betekent dat het subnet geen vrije IP-adressen meer heeft. Check IPAMD-logs: kubectl logs -n kube-system -l k8s-app=aws-node -c aws-node.
  • Generiek: network plugin is not ready: cni config uninitialized betekent dat er geen CNI-configuratie bestaat in /etc/cni/net.d/ op de node. De CNI DaemonSet is nooit gedeployed of draait niet op die node.

Diagnose:

# Check CNI DaemonSet pods
kubectl get pods -n kube-system -l k8s-app=calico-node     # Calico
kubectl get pods -n kube-system -l app=aws-node             # AWS VPC CNI
kubectl get pods -n kube-system -l k8s-app=cilium           # Cilium

# Bekijk CNI-podlogs
kubectl logs -n kube-system <cni-pod-name>

# Check nodestatus (NotReady wijst vaak op netwerkproblemen)
kubectl describe node <node-name> | grep -A5 Conditions

Oplossingen per scenario:

CNI DaemonSet pod crasht of is niet ready:

kubectl rollout restart daemonset calico-node -n kube-system

IP-adrespool uitgeput (AWS VPC CNI):

  • Voeg meer nodes toe om de IP-vraag te verdelen.
  • Koppel extra subnets aan de nodegroup.
  • Schakel prefix delegation in om /28-prefixes per ENI toe te wijzen in plaats van individuele IP's. Dat verhoogt de dichtheid van grofweg 30 naar 110 pods per node op m5.large-instanties.

Node heeft geen CNI-configuratie: Een nieuw toegevoegde node kan 30–60 seconden nodig hebben voordat de CNI DaemonSet pod start en zijn config schrijft. Als de node langer in deze staat blijft, controleer dan of de nodeSelector en tolerations van de DaemonSet het toestaan om op die node te draaien.

Je weet dat het gelukt is als: kubectl describe pod geen FailedCreatePodSandBox-events meer toont en de pod een IP-adres krijgt (zichtbaar in kubectl get pods -o wide).

Init containers die blokkeren

Init containers draaien sequentieel voordat de main containers starten. Elke init container moet met exit code 0 afsluiten voordat de volgende begint. Een pod waarbij init containers nog draaien toont Init:N/M in kubectl get pods, niet ContainerCreating.

Dat verschil is belangrijk. Als je Init:0/2 ziet, is het probleem de init container, niet de setup van de main container. Als je ContainerCreating ziet, zijn alle init containers al afgerond maar blokkeert er iets anders (volume, secret, CNI).

kubectl STATUS Betekenis
Init:N/M N van M init containers afgerond; wacht op meer
Init:Error Een init container is gestopt met een non-zero exit code
Init:CrashLoopBackOff Een init container faalt herhaaldelijk met backoff
PodInitializing Alle init containers klaar; main containers starten
ContainerCreating Main containers worden opgezet (init containers al geslaagd)

Vastgelopen init containers diagnosticeren:

# Bekijk init container states en exit codes
kubectl describe pod <pod-name> -n <namespace>
# Kijk naar de "Init Containers:" sectie

# Haal init container logs op
kubectl logs <pod-name> -c <init-container-name> -n <namespace>

# Als de container al gestopt is:
kubectl logs <pod-name> -c <init-container-name> -n <namespace> --previous

Veelvoorkomende oorzaken:

  1. Wachten op een dependency die nooit beschikbaar komt. De init container draait een wait-for-it-loop die een database of externe service controleert. Als de dependency down is of DNS niet werkt, loopt de loop eindeloos door. Debug DNS: kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- nslookup <service-name>.<namespace>.svc.cluster.local.
  2. Image-pullfout van de init container. Toont zich als ImagePullBackOff op de init container specifiek. Check de Init Containers-sectie in de describe-output en zie ImagePullBackOff troubleshooting.
  3. Script stopt met non-zero exit code. Check logs: kubectl logs <pod> -c <init-container-name>. Voeg set -x toe aan shell-gebaseerde init scripts voor verbose tracing.
  4. Resourcelimieten te krap. CPU-throttling of OOM zorgt ervoor dat de init container wordt gekilld of te langzaam draait. Verhoog resources.limits.

Je weet dat het gelukt is als: kubectl get pods toont dat de status vordert van Init:N/M via PodInitializing naar Running.

Diagnostische beslisboom

Pod vastgelopen in ContainerCreating
|
+-- kubectl describe pod --> Events-sectie
|   |
|   +-- FailedAttachVolume / FailedMount
|   |   +-- PVC Pending? --> StorageClass, provisioner, access mode
|   |   +-- Multi-Attach-fout? --> Stale VolumeAttachment, Recreate-strategie
|   |   +-- CSI-fout? --> CSI-driverstatus
|   |
|   +-- Failed: secret/configmap not found --> Resource aanmaken, pod herstarten
|   |
|   +-- FailedCreatePodSandBox --> CNI-pluginstatus, IP-uitputting
|   |
|   +-- Geen events --> Check kubelet-logs (journalctl -u kubelet)
|
+-- kubectl get pods toont Init:N/M --> Niet ContainerCreating
    +-- kubectl logs <pod> -c <init-container-name>

Wanneer escaleren

Als de oorzaak niet overeenkomt met bovenstaande scenario's, of als oplossingen het probleem niet verhelpen, verzamel dan deze informatie voordat je hulp vraagt:

  • Volledige output van kubectl describe pod <pod-name> -n <namespace>
  • Pod events: kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name> --sort-by='.lastTimestamp'
  • PVC-status (als volumes betrokken zijn): kubectl describe pvc <pvc-name> -n <namespace>
  • VolumeAttachment-objecten: kubectl get volumeattachment -o yaml
  • CNI-podlogs (bij sandbox-creatiefout): kubectl logs -n kube-system <cni-pod-name>
  • Kubelet-logs van de doelnode: journalctl -u kubelet --since "30 minutes ago"
  • Kubernetes-versie: kubectl version
  • Het pod- of Deployment-manifest (ontdaan van secrets)

Herhaling voorkomen

  • Valideer resources voor je deployt. kubectl get configmaps,secrets -n <namespace> voordat je kubectl apply uitvoert. CI-pipelines kunnen deze check automatiseren.
  • Gebruik de Recreate-strategie voor Deployments met RWO-volumes. RollingUpdate met een single-replica Deployment die een ReadWriteOnce-volume gebruikt, triggert altijd Multi-Attach-fouten.
  • Monitor PVC-bindingsstatus. Met kube-state-metrics vangt kube_persistentvolumeclaim_status_phase{phase="Pending"} ongebonden PVC's op voordat pods ze refereren.
  • Zet fsGroupChangePolicy: OnRootMismatch op workloads die grote volumes mounten met fsGroup. Dat voorkomt recursieve ownership-wijzigingen bij elke pod-restart.
  • Houd CNI DaemonSets gezond. Alert op kube_daemonset_status_number_unavailable{daemonset=~".*cni.*|calico-node|aws-node|cilium"} om CNI-podfouten te detecteren voordat ze nieuwe pods blokkeren.

Terugkerende server- of deploymentproblemen?

Ik help teams productie betrouwbaar maken met CI/CD, Kubernetes en cloud—zodat fixes blijven en deploys geen stress meer zijn.

Bekijk DevOps consultancy

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.