Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

A Kubernetes API Request: End-to-End Flow

By Kokil Thapa | Last reviewed: September 2026

Every cluster change starts the same way: something sends an HTTP request to the API server. Understanding A Kubernetes API Request: End-to-End Flow is what separates guessing from fixing. You run kubectl apply, hit an Ingress controller, or call the REST API from a Laravel job. The path is identical at the core. This guide traces that path from client to etcd, through controllers, and down to the kubelet. It also shows where auth, admission, and watches fit in. If you run production workloads, this is the mental model you need before you tune resource limits or chase a CrashLoop.

What happens when you send a Kubernetes API request?

The Kubernetes API is RESTful and versioned. Every object lives under a group, version, and resource path. A Pod in the default namespace uses /api/v1/namespaces/default/pods. A Deployment uses /apis/apps/v1/namespaces/default/deployments.

Clients never talk to etcd directly. They talk only to kube-apiserver. That single gatekeeper is deliberate. It enforces auth, validation, defaulting, and optimistic concurrency. It also emits watch events so controllers stay in sync.

When you run:

kubectl apply -f deployment.yaml --v=8

you see the full HTTP conversation. Raise verbosity to trace TLS, headers, request bodies, and response codes. That log is your first debug tool when a change never reaches the cluster.

Kubernetes API Request PathClientkubectl / SDKkube-apiserverHTTPS :6443etcdcluster stateControllerswatch + reconcilekubeletnode agentParallel pathsScheduler assigns PodsCNI sets up networkCSI mounts volumeskube-proxy routes traffic
A Kubernetes API request end-to-end flow: client to API server, persistence in etcd, then controllers and kubelets reconcile desired state.

The API server exposes OpenAPI schemas. Tools like kubectl explain pod.spec read those schemas at runtime. Official reference lives in the Kubernetes API reference. That doc is the source of truth for fields, defaults, and status subresources.

How does the kube-apiserver authenticate and authorize a request?

Before any object is read or written, the API server runs a fixed pipeline. Authentication answers who you are. Authorization answers what you may do. Admission mutates or validates the object before persistence.

Authentication (AuthN)

Common authenticators include:

  • Client certificates — embedded in kubeconfig for humans and components
  • Service account tokens — mounted into Pods at /var/run/secrets/kubernetes.io/serviceaccount/token
  • OIDC tokens — used with identity providers in many production clusters
  • Webhook token review — custom validation for bearer tokens

Human kubeconfig files store cluster URL, credentials, and context. Inspect yours:

kubectl config view --minify
kubectl auth can-i create deployments --namespace=production

The second command hits the SelfSubjectAccessReview API. It is the fastest way to test RBAC without applying a broken manifest.

Authorization (AuthZ)

RBAC is the default mode. A Role or ClusterRole lists verbs on resources. A binding attaches that role to a user, group, or ServiceAccount.

Example Role for a read-only dashboard:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: apps
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

Authorization modules run in order: RBAC, Node, Webhook. The first allow wins. A deny from webhook auth blocks the call even if RBAC would permit it.

Admission control

After AuthN and AuthZ pass, mutating admission webhooks run first. They can inject sidecars, set defaults, or rewrite labels. Validating webhooks reject bad objects. Built-in plugins enforce PodSecurity, ResourceQuota, and LimitRange.

A typical failure here looks like:

Error from server: admission webhook "validate.example.com" denied the request:
container cpu limit must be set

That message means your request never reached etcd. Fix the manifest or webhook policy. See our guide on requests and limits for the fields webhooks often require.

API Server Request PipelineTLS + AuthNAuthZ RBACMutatingValidatingetcd persistCommon rejection points401 invalid token · 403 RBAC deny · 422 schema fail409 conflict · webhook timeout · quota exceeded
Every Kubernetes API request passes authentication, RBAC authorization, and admission before the API server writes to etcd.

Details on auth modules are in the official authentication documentation. Pair that with our API security checklist when you expose services outside the cluster.

How does etcd store and return Kubernetes API objects?

etcd is a consistent, distributed key-value store. The API server maps each object to a key under /registry/.... Writes use resourceVersion for optimistic concurrency. If two clients patch the same object, the second gets HTTP 409 Conflict.

Reads can be:

  1. Direct get/list — one round trip from client through API server to etcd
  2. Watch — long-lived HTTP stream of change events from a given resourceVersion
  3. Cache served — API server serves lists from an in-memory watch cache for speed

Controllers depend on watches. When you create a Deployment, the deployment controller watches ReplicaSets. The ReplicaSet controller watches Pods. The scheduler watches unscheduled Pods. Each component reacts to API events without polling etcd.

etcd performance affects the whole cluster. Slow disks or high write churn raise API latency. Backups matter. A corrupted etcd store means a corrupted cluster brain. The etcd documentation covers snapshot and restore procedures you should rehearse before an incident.

resourceVersion and consistency

Every object carries metadata.resourceVersion. Clients send it on update to ensure they modify the latest copy. Watches start at a version so you do not miss events between list and watch.

kubectl get pods -o json | jq '.items[0].metadata.resourceVersion'
kubectl get pods --watch-only

If you build operators or custom controllers, treat resourceVersion carefully. A stale version causes retry loops or missed state. Our article on operators that extend the API covers controller patterns in depth.

What is the difference between read and write API request paths?

Not every API call follows the full write pipeline. Reads skip admission for existing objects. Writes always pass validation. Subresources like /status and /scale have separate paths and RBAC rules.

AspectRead (GET/LIST/WATCH)Write (CREATE/UPDATE/PATCH/DELETE)
AuthN / AuthZRequiredRequired
Admission webhooksNot on simple readsMutating + validating run
etcd interactionRead or watch streamTransactional write
Side effectsNone by itselfControllers reconcile change
Typical latencyLower; cache helps listsHigher; validation + persistence
Debug commandkubectl get --v=8kubectl apply --v=8

Status updates often use a dedicated subresource. Kubelet patches pods/status with observed state. Controllers patch deployments/status with replica counts. Splitting spec and status stops privilege escalation. A Pod editor should not fake a Running phase.

Server-side apply (SSA) changed how writes merge field ownership. With kubectl apply --server-side, the API tracks managers per field. Conflicts surface as explicit errors instead of silent overwrites. That matters when GitOps tools and operators manage the same object.

Read vs Write API PathsREAD pathGET / LIST / WATCHAuthN + AuthZCache or etcd readJSON responseWRITE pathCREATE / PATCH / DELETEAuthN + AuthZAdmission webhooksetcd write + watch fanout
Read and write Kubernetes API requests share auth but differ after admission and etcd persistence on mutating calls.

How do controllers and kubelets complete a Kubernetes API request?

Persistence in etcd is not the end. It is the start of reconciliation. The API server publishes watch events. Controllers compare desired state in etcd with actual cluster state. They issue more API writes until the gap closes.

Example: creating a Deployment

Follow this sequence when you kubectl apply -f deployment.yaml:

  1. API server validates the Deployment and stores it in etcd.
  2. Deployment controller sees the new object. It creates a ReplicaSet via another API write.
  3. ReplicaSet controller creates Pod objects. Pods land in etcd with no node assigned.
  4. Scheduler watches unscheduled Pods. It patches spec.nodeName on one Pod at a time.
  5. Kubelet on that node watches Pods bound to itself. It pulls the image and starts containers.
  6. Kubelet patches pod/status with conditions and container states.
  7. Deployment controller reads ReplicaSet status. It scales up or down if counts drift.

Each arrow is another API request. A single apply can trigger dozens of internal calls. That is normal. It also explains why RBAC for controllers uses broad permissions. They are API clients too.

Network and storage add parallel paths. CNI plugins react to Pod sandbox events. CSI drivers attach volumes when PersistentVolumeClaims bind. NetworkPolicy objects filter traffic once Pods exist. None of that bypasses the API server.

From application code

When a Laravel app runs inside the cluster, it should use in-cluster config. The ServiceAccount token and CA cert mount automatically. Official client libraries handle TLS and discovery.

/* PHP example using kubernetes/client-php */
$config = Kubernetes\Client\Config::getInClusterConfig();
$client = new Kubernetes\Client\Client($config);
$pods = $client->coreV1()->listNamespacedPod('production');

Outside the cluster, use a kubeconfig with limited RBAC. Never embed cluster-admin credentials in application env vars. For patterns on signing outbound calls, see Laravel signed API requests and building RESTful APIs with Laravel. If you are new to running PHP on clusters, start with Kubernetes for Laravel getting started.

On a booking platform I helped deploy, background jobs scaled worker Pods through the API during peak hours. The same flow applied: authenticated PATCH to Deployment scale, etcd update, controller reconcile, kubelet start. Understanding that chain made a five-minute lag traceable to scheduler backlog, not a mystery "Kubernetes delay".

Deployment Create: API Call ChainDeploymentReplicaSetPod objectsSchedulerkubeletEach step = new API writeWatch events drive loopsStatus subresource updatesHPA reads metrics APIProbe failures patch statusEvents recorded via API
One Deployment create triggers a chain of Kubernetes API requests through controllers, the scheduler, and kubelet status updates.

How do you debug a failed Kubernetes API request?

Start at the edge. Split failures into client-side, API server, admission, and reconciliation problems. Each layer has distinct symptoms and tools.

Client and transport errors

Connection refused on port 6443 means wrong server URL or firewall. Certificate errors mean expired apiserver cert or wrong CA in kubeconfig. Fix kubeconfig before chasing RBAC.

kubectl cluster-info
kubectl get --raw /healthz
kubectl get --raw /readyz

The raw health endpoints bypass most auth. They confirm the API server process is alive.

403 Forbidden vs 404 Not Found

403 means authenticated but not authorized. Check RoleBindings and whether you target the right namespace. 404 on namespaced resources often means typo in name or namespace. It can also mean the CRD is not installed.

kubectl auth can-i --list --namespace=target-ns
kubectl api-resources | grep mycrd

Admission and validation failures

Read the exact webhook name in the error. Inspect webhook configuration and backend service health. Timeouts often trace to a Pod in kube-system that cannot reach the API or has cert issues.

Object exists but nothing runs

The write succeeded. Reconciliation failed. Check controller logs in kube-system. Describe the object and read Events:

kubectl describe pod my-app-7d4f8b9c-xk2lm
kubectl get events --sort-by=.metadata.creationTimestamp

Common post-API failures include image pull errors, insufficient CPU on nodes, and volume mount failures. Our guide on debugging CrashLoopBackOff walks through kubelet-level symptoms. For batch work, see Jobs and CronJobs.

Audit logs and API priority

Enable audit logging on the API server for compliance and forensics. Audit entries show user, verb, resource, response code, and latency. Pair audit with Horizontal Pod Autoscaling metrics when scale events look wrong.

API Priority and Fairness (APF) protects the API server from overload. Noisy controllers or runaway watches can queue or reject requests with 429 Too Many Requests. If many clients retry at once, you get a retry storm. Back off exponentially in automation.

Gateway and ingress layers

Traffic into the cluster is a separate path. An API gateway like Kong or an Ingress controller terminates HTTP and routes to Services. That path does not replace the Kubernetes API. It sits in front of your app Pods. Confusing the two leads to debugging Ingress when the real issue is RBAC on a Job that never ran.

When you inspect JSON responses during integration work, paste payloads into the JSON formatter to compare fields against OpenAPI docs. Small schema mismatches cause 422 errors before etcd ever sees data.

Key Takeaways

  • All cluster changes flow through kube-apiserver over HTTPS; clients never write etcd directly.
  • Every write passes AuthN, AuthZ, mutating admission, validating admission, then etcd persistence.
  • Controllers and kubelets are API clients that watch and reconcile; one kubectl apply triggers many internal requests.
  • Use kubectl auth can-i, --v=8, and describe Events to locate failures by pipeline stage.
  • Separate spec and status subresources; patch status with limited RBAC to reduce blast radius.
  • Protect etcd performance and backups; API latency and disaster recovery both depend on it.

People Also Ask

Does kubectl talk directly to Pods or nodes?

No. kubectl sends requests only to kube-apiserver. Commands like kubectl logs and kubectl exec are API subresource calls. The API server proxies them to the kubelet on the target node. The kubelet then reads container logs or attaches to a process namespace.

What is the difference between the Kubernetes API and the aggregation layer?

The core API server handles built-in resources. The aggregation layer forwards requests for extension APIs to registered extension API servers. Metrics, custom metrics, and many operator CRDs use this path. Authentication still runs in the main API server before the request is delegated.

Why do I get 409 Conflict on kubectl apply?

HTTP 409 means optimistic concurrency failed. Another client changed the object after you read it. Your resourceVersion is stale. Retry with a fresh get, or use server-side apply with explicit field managers to reduce merge fights between GitOps and controllers.

How do ServiceAccounts authenticate API requests from inside a Pod?

The cluster mounts a JWT token, CA bundle, and namespace file into the Pod. Client libraries read these paths to build TLS connections. RBAC binds the ServiceAccount to Roles. Tokens can be bound and rotated; legacy long-lived secrets are deprecated in favor of bound tokens with audience claims.

Put the Kubernetes API request flow to work on your stack

A Kubernetes API Request: End-to-End Flow is the spine of every deploy, scale, and heal action in your cluster. Once you see auth, admission, etcd, watches, and reconciliation as one chain, incidents get shorter. You know which log to open and which HTTP code points where.

If you are wiring Laravel services, payment callbacks, or CI pipelines into a cluster and want that architecture reviewed end to end, see our API development services and Linux system administration offerings. For a production example of an app stack reconciled through automated deploys, browse the Adventure Third Pole Trek portfolio entry.

Contact us to audit your cluster API usage, RBAC model, or application integration path before your next production cutover.

Frequently Asked Questions

The request hits kube-apiserver over HTTPS, passes authentication and authorization, runs admission webhooks, then reads or writes etcd. Controllers and kubelets reconcile the change afterward.

No. kubectl sends requests only to kube-apiserver. Commands like kubectl logs and kubectl exec are API subresource calls proxied to the kubelet on the target node.

HTTP 409 means optimistic concurrency failed. Another client changed the object after you read it. Your resourceVersion is stale; retry with a fresh get or use server-side apply.

Before any read or write, the API server runs a fixed pipeline. Authentication answers who you are using client certificates in kubeconfig, ServiceAccount tokens mounted at /var/run/secrets/kubernetes.io/serviceaccount/token, OIDC tokens, or webhook token review. Authorization then checks RBAC Roles and bindings; modules run in order (RBAC, Node, Webhook) and the first allow wins. Test access with kubectl auth can-i without applying a broken manifest. Only after both stages pass do mutating and validating admission webhooks run.

Admission runs after authentication and authorization, before etcd persistence. Mutating admission webhooks run first and can inject sidecars, set defaults, or rewrite labels. Validating webhooks then reject objects that violate policy. Built-in plugins enforce PodSecurity, ResourceQuota, and LimitRange. A typical failure looks like admission webhook validate.example.com denied the request: container cpu limit must be set. That means your request never reached etcd; fix the manifest or webhook policy, not RBAC or kubelet logs.

etcd is a consistent, distributed key-value store. The API server maps each object to a key under /registry/ and never lets clients write etcd directly. Writes use resourceVersion for optimistic concurrency; a stale patch returns HTTP 409 Conflict. Reads can be a direct get or list, a long-lived watch stream from a resourceVersion, or a list served from the API server in-memory watch cache for speed. Controllers depend on watches, not polling etcd. Slow etcd disks or high write churn raise API latency cluster-wide, so snapshot backups matter.

Both require authentication and authorization, but they diverge after that. Reads on existing objects skip admission webhooks; writes always pass mutating and validating admission before a transactional etcd write. Reads are usually lower latency because list responses can come from the watch cache. Writes trigger controller reconciliation and often more API calls. Subresources like /status and /scale have separate paths and RBAC rules so a Pod editor cannot fake a Running phase. Debug reads with kubectl get --v=8 and writes with kubectl apply --v=8 to see where the pipeline stops.

The core kube-apiserver handles built-in resources such as Pods, Deployments, and Services under paths like /api/v1 and /apis/apps/v1. The aggregation layer forwards requests for extension APIs to registered extension API servers. Metrics, custom metrics, and many operator CRDs use this delegated path. Authentication still runs in the main API server before the request is forwarded. Clients still talk to one HTTPS endpoint; they do not call extension servers directly. If a CRD returns 404, check whether the extension API server is registered and healthy.

Persistence in etcd is only the start. The API server validates and stores the Deployment. The deployment controller watches that event and creates a ReplicaSet via another API write. The ReplicaSet controller creates Pod objects with no node assigned. The scheduler watches unscheduled Pods and patches spec.nodeName on one Pod at a time. The kubelet on that node watches bound Pods, pulls the image, starts containers, and patches pod/status with observed state. The deployment controller then scales if replica counts drift. One apply can trigger dozens of internal API requests; that is normal cluster behavior.

Controllers and kubelets are API clients, not bypass paths around kube-apiserver. After a write lands in etcd, the API server publishes watch events. Each controller compares desired state in etcd with actual cluster state and issues more API writes until the gap closes. The scheduler patches Pod spec; kubelets patch pod/status. CNI plugins, CSI drivers, and NetworkPolicy enforcement also react once objects exist, but none of that skips the API server. Broad controller RBAC exists because reconciliation is a chain of authenticated writes, not a single kubectl apply.

Split failures by pipeline stage. Client errors on port 6443 mean wrong server URL, firewall, or bad CA in kubeconfig; confirm with kubectl cluster-info and kubectl get --raw /healthz. HTTP 403 means authenticated but not authorized; use kubectl auth can-i --list in the target namespace. HTTP 404 often means a typo, wrong namespace, or missing CRD; check with kubectl api-resources. Admission errors name the webhook directly. If the object exists but nothing runs, reconciliation failed; use kubectl describe and kubectl get events, then check controller logs in kube-system.

Every Kubernetes object carries metadata.resourceVersion, an etcd revision marker the API server uses for optimistic concurrency. Clients send it on update so two writers cannot silently overwrite each other; a stale version returns HTTP 409 Conflict. Watches start at a resourceVersion so you do not miss events between a list and a watch. Inspect it with kubectl get pods -o json and jq on metadata.resourceVersion. If you build operators or custom controllers, treat resourceVersion carefully; stale versions cause retry loops or missed state during reconciliation.

After AuthN and AuthZ pass, mutating admission webhooks run first, then validating webhooks. A validating webhook rejection stops persistence entirely. The error names the webhook, for example admission webhook validate.example.com denied the request: container cpu limit must be set. Fix the manifest fields the policy requires or adjust the webhook configuration. Timeouts often trace to a kube-system Pod that cannot reach the API server or has certificate issues. RBAC fixes will not help because the object never reached etcd; inspect webhook backend service health and webhook configuration instead.

HTTP 403 means the request authenticated successfully but RBAC or a webhook authorization module denied the action. Check RoleBindings, ClusterRoleBindings, and whether you target the correct namespace. HTTP 404 on a namespaced resource usually means a typo in the name or namespace, or the CustomResourceDefinition is not installed. Use kubectl auth can-i --list --namespace=target-ns for authorization problems and kubectl api-resources | grep mycrd when a custom resource type is missing. Confusing the two sends you fixing manifests when the real issue is permissions.

A Pod should use in-cluster config, not embedded cluster-admin credentials in environment variables. Kubernetes mounts the ServiceAccount token and CA certificate automatically; official client libraries handle TLS and discovery. In PHP you can use kubernetes/client-php with Kubernetes\Client\Config::getInClusterConfig() and list resources such as namespaced Pods. Outside the cluster, use a kubeconfig with limited RBAC scoped to what the job needs. On a booking platform I helped deploy, background jobs scaled worker Deployments through authenticated PATCH calls during peak hours; the same end-to-end API flow applied.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: