When you run kubectl apply -f <file.yaml>, here’s what happens step by step:
1. Client-side (kubectl)
- kubectl reads and parses the YAML/JSON manifest
- It serializes it and sends an HTTP PATCH (or POST if new) request to the Kubernetes API server
2. API Server receives the request
- Authentication — is the caller who they say they are? (cert, token, OIDC)
- Authorization — does this user/serviceaccount have RBAC permission to create/update this resource?
- Admission Controllers — the request passes through mutating then validating webhooks (e.g. OPA/Gatekeeper can reject it here, cert-manager webhooks can mutate it, Pod Security Admission enforces SCCs/PSA)
- Schema validation — does the object match the CRD or built-in schema?
3. Persisted to etcd
- Once approved, the desired state is written to etcd — the cluster’s source of truth
- At this point
kubectl applyreturns success to you
4. Controllers react (the reconciliation loop)
- The relevant controller (Deployment controller, ReplicaSet controller, StatefulSet controller, etc.) is watching etcd via the API server
- It detects the delta between desired state (what you just wrote) and current state (what’s running)
- It acts to close that gap — e.g. creates Pods, updates a ReplicaSet
5. Scheduler
- New/unscheduled Pods are picked up by the kube-scheduler
- It evaluates node selectors, taints/tolerations, affinity rules, resource requests, and picks the best node
- It writes the node assignment back to etcd
6. kubelet on the target node
- The kubelet on the assigned node watches for Pods bound to it
- It calls the container runtime (containerd / CRI-O) to pull images and start containers
- It sets up volumes, mounts secrets/configmaps, configures liveness/readiness probes
- It reports Pod status back to the API server
7. kube-proxy / CNI
- If a Service was part of your manifest, kube-proxy updates iptables/ipvs rules on all nodes
- The CNI plugin (OVN-Kubernetes, Calico, Cilium, etc.) wires up the Pod network and applies NetworkPolicies
The key mental model is declarative reconciliation — you describe what you want, and Kubernetes continuously works to make reality match that description. Every controller runs an infinite loop: observe → diff → act.