Stage 5 · Platform
Kubernetes Architecture Deep Dive
API Machinery
REST, watch, informers, caches, and the resource version.
API Request Flow
Every kubectl command, controller action, and kubelet heartbeat flows through the API server. The request passes through authentication, authorization, admission control, and validation before being persisted to etcd. Understanding this pipeline is critical for debugging permission errors and performance issues.
Client Request
|
v
Authentication (who are you?)
|
v
Authorization (what can you do?)
|
v
Admission Control (is this request allowed?)
|
v
Validation (is the object valid?)
|
v
Persistence (write to etcd)
|
v
Response + Watch EventEach stage can reject the request. A rejected request returns a 401 (authn), 403 (authz), or 422 (validation) error. The client receives the first error encountered.
Authentication
Authentication identifies who is making the request. Kubernetes supports multiple authentication methods: X.509 client certs, bearer tokens, OpenID Connect (OIDC), service account tokens, and webhook token authentication. These are additive — if any method succeeds, the user is authenticated.
# kube-apiserver flags for OIDC
--oidc-issuer-url=https://accounts.google.com
--oidc-client-id=kubernetes
--oidc-username-claim=email
--oidc-groups-claim=groups
--oidc-ca-file=/etc/kubernetes/pki/oidc-ca.crtOIDC lets you authenticate with external identity providers (Google, GitHub, Okta). The API server validates the JWT token against the issuer's public keys. Groups claim maps to Kubernetes groups for RBAC.
Service accounts are per-namespace identities for pods. Their tokens are projected into pods at /var/run/secrets/kubernetes.io/serviceaccount/token. In v1.24+, tokens are bound to the pod's lifetime and audience by default (bound service account tokens).
Authorization
Authorization determines what the authenticated user can do. Kubernetes uses RBAC (Role-Based Access Control) as the standard authorization mode. RBAC maps users/groups to roles via RoleBinding and ClusterRoleBinding objects.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list"]Roles are namespace-scoped. The apiGroups field specifies which API group the resource belongs to. Core resources (pods, services) are in the empty string group. Extensions like deployments are in apps.
Admission Control
Admission controllers intercept requests after authorization but before persistence. They can mutate (change the object) or validate (reject invalid objects). Built-in admission controllers include LimitRanger, ResourceQuota, and NodeRestriction. Custom admission webhooks extend this with external logic.
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector
webhooks:
- name: sidecar.injector.example.com
admissionReviewVersions: ["v1"]
sideEffects: None
clientConfig:
service:
name: webhook-server
namespace: kube-system
path: /inject
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
namespaceSelector:
matchLabels:
sidecar-injection: enabledMutating webhooks run in the order defined. They can add init containers, sidecars, volumes, or environment variables to pods. The namespaceSelector controls which namespaces are affected.
Watch Mechanism
Controllers don't poll the API server — they use the watch mechanism. A watch is a long-lived HTTP connection that streams events (Added, Modified, Deleted) as objects change. This is how controllers react to state changes in near real-time without constant polling.
# Watch for pod events
kubectl get pods -w
# Watch with JSON output for scripting
kubectl get pods -o json | jq -c '
.items[] | {
name: .metadata.name,
phase: .status.phase,
ready: (.status.conditions[]? | select(.type=="Ready") | .status)
}'The -w flag opens a watch connection. The server streams events as they happen. This is how client-go's informer cache stays up to date without polling.
Resource Version
Every Kubernetes object has a resourceVersion field — an opaque string that changes on every write. It is used for optimistic concurrency (preventing lost updates) and for resuming watches. If you get a conflict error, your resourceVersion is stale — re-read the object and try again.
resourceVersion is not a timestamp or sequence number. It is an opaque value managed by etcd. You can only use it for comparison (equal or not equal) and for watch bookmarks. Never parse or assume its format.
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
namespace: default
resourceVersion: "12345" # Must match current value
data:
key: "updated-value"If another client modifies the ConfigMap between your read and write, the resourceVersion will differ and the API server returns a 409 Conflict. This prevents lost updates without locking.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.