Guide contents

Lesson 81 of 129

Kubernetes Basics

Kubernetes is a container orchestrator. Users declare the desired state of a system (which containers, how many replicas, what network exposure), and Kubernetes runs control loops that continuously move the actual state toward that desired state. It automates placement, restarts, scaling, service networking, and rolling updates for containers across a cluster of machines.

Architecture

A cluster has a control plane that makes decisions and worker nodes that run workloads.

graph TB
    U["kubectl / CI"] --> API
    subgraph CP["Control plane"]
        API["kube-apiserver"]
        ETCD[("etcd")]
        SCH["kube-scheduler"]
        CM["kube-controller-manager"]
        API <--> ETCD
        SCH --> API
        CM --> API
    end
    subgraph N1["Worker node"]
        K1["kubelet"]
        P1["kube-proxy"]
        CR1["container runtime"]
        POD1["Pods"]
        K1 --> CR1 --> POD1
    end
    K1 --> API
    P1 --> API
Component Role
kube-apiserver The only entry point. Validates and stores objects, and serves watches. All other components talk to it.
etcd A consistent key-value store (built on Raft) holding all cluster state.
kube-scheduler Assigns unscheduled pods to nodes.
kube-controller-manager Runs controllers, each a loop that compares desired and actual state and acts. Examples: the Deployment, ReplicaSet, and Node controllers.
kubelet Agent on each node. Watches for pods assigned to its node, asks the container runtime to run them, runs probes, and reports status.
kube-proxy Programs node networking rules so that traffic to a Service address reaches its pods. Some network plugins replace it.
Container runtime Runs containers through the Container Runtime Interface, for example containerd or CRI-O.

Controllers do not call each other directly. They read and write objects through the API server, and react to changes through watches. This is the reconciliation loop pattern: observe, compare with desired state, act, repeat.

What happens when a Deployment is created

  1. kubectl apply sends the Deployment to the API server, which validates it and stores it in etcd.
  2. The Deployment controller sees the new object through a watch and creates a ReplicaSet. The ReplicaSet controller creates Pod objects that have no node assigned.
  3. The scheduler sees unassigned pods, selects a node for each, and writes the node name into the pod object.
  4. The kubelet on that node sees a pod assigned to it, pulls the image, starts the containers through the container runtime, and reports the pod status to the API server.

Pod

A Pod is the smallest deployable unit. It holds one or more containers that share a network namespace (one IP address, shared localhost) and can share volumes. Containers in a pod are scheduled together onto the same node.

  • Most pods have one application container.
  • A sidecar container in the same pod adds a supporting function, such as a proxy or log shipper (see service mesh and sidecars).
  • Pods are ephemeral. A pod that is deleted or whose node fails is not brought back. A higher-level controller creates a replacement with a new name and IP.

Deployment

A Deployment manages stateless pods through ReplicaSets. The user specifies a pod template and a replica count. The Deployment controller creates a ReplicaSet that keeps that many pods running.

When the template changes (for example a new image tag), the Deployment creates a new ReplicaSet and shifts replicas from the old one gradually. This is a rolling update, controlled by two settings:

  • maxSurge: how many pods above the desired count may exist during the update.
  • maxUnavailable: how many pods below the desired count may be unavailable.

With 3 replicas, maxSurge: 1 and maxUnavailable: 0 (as in the example below), the controller starts one new pod (4 in total), waits until it is ready, then terminates one old pod, and repeats. At least 3 ready pods exist throughout, which requires the readiness probe to be accurate.

The old ReplicaSet is retained, which allows kubectl rollout undo to return to the previous version.

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders
spec:
  replicas: 3
  selector:
    matchLabels: { app: orders }
  strategy:
    type: RollingUpdate
    rollingUpdate: { maxSurge: 1, maxUnavailable: 0 }
  template:
    metadata:
      labels: { app: orders }
    spec:
      containers:
        - name: orders
          image: registry.example.com/orders:1.4.2
          ports: [{ containerPort: 8080 }]
          resources:
            requests: { cpu: "250m", memory: "256Mi" }
            limits: { memory: "512Mi" }
          readinessProbe:
            httpGet: { path: /ready, port: 8080 }

Selection uses labels: key-value pairs on objects. A selector matches objects by label. Deployments, Services, and many other objects are connected this way rather than by name.

Service

Pod IPs change as pods are replaced. A Service gives a group of pods a stable virtual IP and DNS name, and load balances across the ready pods that match its label selector. Only pods that pass their readiness probe are in the Service's endpoints (see health checks and graceful degradation).

Type Behavior
ClusterIP Virtual IP reachable only inside the cluster. Default.
NodePort Also opens a port on every node that forwards to the Service.
LoadBalancer Also provisions an external load balancer from the cloud provider.
ExternalName Returns a DNS CNAME to an external name.
Headless (clusterIP: None) No virtual IP. DNS returns the individual pod IPs. Used by StatefulSets.

Cluster DNS gives each Service a name such as orders.shop.svc.cluster.local (<service>.<namespace>.svc.<cluster-domain>). This is the basis of service discovery in Kubernetes.

Ingress

An Ingress is an object that describes HTTP(S) routing from outside the cluster to Services: host and path rules, and TLS certificates. An ingress controller (for example NGINX-based or Envoy-based) is a running component that implements those rules. The Ingress object has no effect without a controller. The Gateway API is a newer, more expressive set of resources for the same purpose. Functionally this layer is a reverse proxy or API gateway at the cluster edge.

Horizontal Pod Autoscaler

The HorizontalPodAutoscaler (HPA) changes a workload's replica count based on metrics. It periodically compares an observed metric to a target and computes:

desiredReplicas = ceil(currentReplicas * currentMetric / targetMetric)

The metric is commonly CPU utilization relative to the pods' CPU requests, so requests must be set. Memory, custom metrics, and external metrics (for example queue length) are also supported. For example, 4 replicas at 90% average CPU utilization with a 60% target gives ceil(4 * 90 / 60) = 6 replicas. The HPA has min and max replica bounds and stabilization windows to prevent oscillation (by default, scale-down decisions use the highest recommendation of the previous 300 seconds). Scaling out only helps if the cluster has node capacity. A separate cluster autoscaler adds nodes when pods cannot be scheduled.

ConfigMap and Secret

A ConfigMap stores non-confidential configuration as key-value pairs. A Secret stores sensitive values such as tokens and keys. Both can be injected as environment variables or mounted as files.

  • Secret values are base64-encoded, which is an encoding and not encryption. Protection depends on enabling encryption at rest for etcd, restricting access with RBAC, and optionally using an external secret store.
  • Environment variables are read at container start. Mounted files are updated in the running container after a delay, but the application must reload them.

See configuration and secrets management.

StatefulSet

A StatefulSet manages pods that need stable identity and storage, such as database replicas.

  • Pods have stable ordinal names (db-0, db-1, db-2) that persist across rescheduling.
  • Each pod gets its own PersistentVolumeClaim, which is reattached to the replacement pod with the same name.
  • Pods are created and updated in order by default.
  • A headless Service gives each pod a stable DNS name.

StatefulSets provide identity and storage attachment. They do not provide replication, backup, or failover for the data. Those come from the database software or an operator.

Scheduling

The scheduler assigns each pod to a node in two phases.

  1. Filtering removes nodes that cannot run the pod: insufficient unreserved CPU or memory compared to the pod's requests, taints the pod does not tolerate, unsatisfied node selectors or affinity rules.
  2. Scoring ranks the remaining nodes and selects the best.
Mechanism Purpose
Resource requests The amount reserved for scheduling decisions.
Resource limits The maximum enforced at run time through cgroups. Exceeding the memory limit gets the container killed. CPU over the limit is throttled.
Node selector / node affinity Restrict pods to nodes with certain labels.
Pod affinity / anti-affinity Place pods near, or away from, other pods. Anti-affinity spreads replicas across nodes.
Topology spread constraints Distribute pods evenly across zones or nodes.
Taints and tolerations A tainted node repels pods unless they tolerate the taint.

Requests and limits also determine the pod's QoS class (Guaranteed, Burstable, BestEffort), which affects eviction order under node memory pressure.

Trade-offs

  • Kubernetes solves scheduling, self-healing, and rollout for many services, but adds operational complexity. Small systems may not justify a cluster (see when to use microservices).
  • Requests set too high waste capacity. Requests set too low cause noisy neighbors and evictions.
  • The control plane is a critical dependency for changes, but running pods keep running if it is briefly unavailable.

Interview questions

  • What happens when a pod crashes or its node fails? The kubelet restarts a crashed container according to the pod's restart policy. If the node fails, it is eventually marked unreachable, and its pods are evicted after a toleration period (300 seconds by default). The controller that owns the pod (for example a ReplicaSet) then sees fewer pods than desired and creates replacements, which the scheduler places on healthy nodes.
  • What is the difference between a liveness and a readiness probe? A failing liveness probe causes the container to be restarted. A failing readiness probe removes the pod from Service endpoints without restarting it.
  • Why use a Service instead of pod IPs? Pod IPs change whenever pods are replaced. A Service provides a stable address and balances across current ready pods.
  • Deployment or StatefulSet? A Deployment suits interchangeable stateless pods. A StatefulSet suits pods that need stable names and their own persistent volumes.
  • What do requests and limits do? Requests are used by the scheduler to place the pod and by the HPA to compute utilization. Limits are enforced on the node by the kernel.