DevOpsKubernetes

Kubernetes Architecture Explained: Control Plane, Nodes & kubectl

Deep dive into Kubernetes architecture. Learn how the API server, etcd, scheduler, controller manager, kubelet, and kube-proxy work together to run containerised workloads.

TT
Daniel Brooks
6 min read
Kubernetes Architecture Explained: Control Plane, Nodes & kubectl

Kubernetes is a distributed system — multiple processes running across multiple machines, coordinating to run your workloads reliably. Understanding the architecture isn't just academic: it helps you debug issues, understand error messages, and reason about what happens when things go wrong.

This lesson digs into every major component, how they talk to each other, and how kubectl fits in.


The Two Parts of a Kubernetes Cluster

A Kubernetes cluster has two types of machines:

  1. Control plane nodes — run the Kubernetes management components; they don't run your application containers (in production)
  2. Worker nodes — run your application Pods

In a production cluster you'll have multiple control plane nodes for high availability. In development (minikube, kind, Docker Desktop), a single node runs everything.


Control Plane Components

The control plane is the brain of Kubernetes. It stores the desired state, schedules workloads, and constantly works to reconcile the actual state of the cluster with what you've declared.

API Server (kube-apiserver)

The API server is the single entry point for all control plane operations. Every interaction with a Kubernetes cluster goes through it — kubectl commands, internal component communication, and external tooling.

It validates and processes REST API requests, authenticates and authorises every request, reads and writes cluster state to etcd, and notifies other components of state changes. The API server is stateless — all state lives in etcd. You can run multiple replicas for high availability.

etcd

etcd is a distributed key-value store and the single source of truth for all cluster state: what Pods exist, what Deployments are configured, which nodes are registered, what Secrets are stored.

Key properties: strongly consistent (reads always return the latest committed value), distributed (typically runs as a 3 or 5 node cluster for fault tolerance), and watched by other components via the API server.

Back up etcd regularly in production. Losing etcd without a backup means losing the entire cluster state.

Scheduler (kube-scheduler)

When a new Pod is created, it's initially unbound — it exists in etcd but isn't assigned to a node. The scheduler watches for unbound Pods and makes placement decisions based on resource requests (does the node have enough CPU and memory?), node selectors and affinity rules, taints and tolerations, and spread constraints.

Once the scheduler decides, it updates the Pod's nodeName field in etcd via the API server. The kubelet on that node picks it up from there.

Controller Manager (kube-controller-manager)

The controller manager runs a collection of controllers — each is an independent reconciliation loop watching for a specific type of resource and ensuring the cluster matches the desired state.

ControllerWhat It Manages
ReplicaSet ControllerEnsures the right number of Pod replicas exist
Deployment ControllerManages rollouts and rollbacks
Node ControllerMonitors node health; evicts Pods from failed nodes
Service Account ControllerCreates default service accounts in new namespaces
Job ControllerManages batch Jobs to completion
EndpointSlice ControllerUpdates Service endpoints when Pods change

Worker Node Components

Worker nodes are where your application Pods actually run. Each node runs three main processes.

kubelet

The kubelet is an agent running on every worker node. It watches the API server for Pods scheduled to its node, instructs the container runtime to start, stop, and monitor containers, reports Pod status and node health back to the API server, and runs liveness and readiness probes.

The kubelet speaks to the container runtime via the Container Runtime Interface (CRI). The default runtime in modern Kubernetes is containerd.

kube-proxy

kube-proxy runs on every node and maintains the network routing rules that make Kubernetes Services work. When you create a Service with a virtual IP, kube-proxy programs iptables rules on every node so that traffic to the Service IP is forwarded to the correct Pod IPs. As Pods come and go, kube-proxy updates these rules automatically.

Container Runtime

The container runtime (containerd, CRI-O) is what actually pulls images and starts/stops containers. The kubelet delegates all container operations to it via the CRI.


How It All Works Together: Pod Creation Flow

Here's what happens step-by-step when you run kubectl apply -f deployment.yaml:

text
1. kubectl → sends YAML to API Server
2. API Server → validates, authenticates, stores desired state in etcd
3. Deployment Controller → watches etcd, sees new Deployment
                          → creates ReplicaSet
4. ReplicaSet Controller → watches etcd, sees new ReplicaSet
                          → creates 3 Pods (unbound)
5. Scheduler → watches for unbound Pods
              → selects a node for each Pod
              → updates Pod.spec.nodeName in etcd
6. kubelet (on selected node) → watches API server
                               → sees Pod assigned to its node
                               → tells containerd to pull image + start container
7. kubelet → reports Pod status (Running) back to API server
8. API server → updates Pod status in etcd

This flow — write desired state → controllers reconcile → containers run — is the engine of Kubernetes.


kubectl: The Kubernetes CLI

kubectl is the command-line client for talking to the Kubernetes API server. It reads your cluster's connection details from ~/.kube/config (the kubeconfig file).

Essential kubectl Commands

bash
# Cluster info
kubectl cluster-info
kubectl get nodes
kubectl get nodes -o wide    # extra detail including IPs

# Namespaces
kubectl get namespaces
kubectl create namespace staging

# Get resources
kubectl get pods
kubectl get pods -n kube-system    # system namespace
kubectl get all                     # pods, services, deployments, etc.

# Describe (human-readable detail + events)
kubectl describe pod my-pod-xyz
kubectl describe node my-node

# Apply and delete
kubectl apply -f deployment.yaml
kubectl delete -f deployment.yaml

# Logs
kubectl logs my-pod-xyz
kubectl logs -f my-pod-xyz         # follow
kubectl logs my-pod-xyz -c api     # specific container in multi-container Pod

# Execute commands
kubectl exec -it my-pod-xyz -- bash

# Port forward (for local testing)
kubectl port-forward pod/my-pod-xyz 3000:3000
kubectl port-forward service/my-service 8080:80

Kubeconfig

yaml
# ~/.kube/config
apiVersion: v1
clusters:
  - cluster:
      server: https://kubernetes.example.com
    name: my-cluster
contexts:
  - context:
      cluster: my-cluster
      user: admin
    name: my-cluster-context
current-context: my-cluster-context

Switch between clusters with:

bash
kubectl config get-contexts
kubectl config use-context my-cluster-context

Previous: Lesson 6 — What Is Kubernetes? | Next: Lesson 8 — Pods, Deployments & Services


Part of the Docker & Kubernetes Mastery course.

External references: