Introduction to Kubernetes Concepts

Kubernetes is a container orchestration platform: it runs containerized applications across a cluster and keeps them in the state you asked for. Docker teaches you images, containers, ports, volumes, and networks; Kubernetes uses those same building blocks but wraps them in higher-level objects for scheduling, self-healing, service discovery, and rolling updates. The important shift is that you stop managing individual containers directly and start declaring application state.

Overview: How Kubernetes Works

A Docker container is one running process created from an image made of read-only layers plus a thin writable layer. Kubernetes does not replace that image model. You still build images with Docker or another OCI-compatible builder, push them to a registry, and run processes from those images. What changes is who decides where containers run, how many copies exist, how they are reached, and what happens after failures.

A Kubernetes cluster has a control plane and one or more worker nodes. The control plane exposes the Kubernetes API, stores desired state, schedules work, and runs controllers that constantly compare desired state with actual state. Worker nodes run a kubelet agent, a container runtime, and networking components. Modern Kubernetes usually runs containers through containerd or another Container Runtime Interface implementation, not through the Docker Engine daemon directly, but the images are still OCI images that Docker can build.

The smallest deployable unit in Kubernetes is a Pod. A Pod wraps one or more tightly related containers that share a network namespace and can share volumes. In most web app cases, a Pod has one application container. Containers inside one Pod can reach each other on localhost, while different Pods get their own IP addresses. Pods are intentionally disposable: if a node fails, the old Pod is gone and a replacement Pod may appear elsewhere with a new IP.

Because Pods are disposable, you rarely create naked Pods for applications. You create a Deployment, which owns a ReplicaSet, which creates Pods from a template. If the Deployment says replicas: 3, Kubernetes tries to keep three matching Pods running. If one exits, a controller creates another. If you change the image tag in the Deployment, Kubernetes performs a rolling update by creating new Pods and terminating old ones according to the rollout rules.

A Service gives a stable network identity to a changing set of Pods. It selects Pods by labels, such as app: web, and gives other workloads a steady DNS name and virtual IP. This solves a problem Docker users recognize from scaling: individual container or Pod IPs are not stable, so clients should connect to a service name instead of a specific replica. For public traffic, clusters usually add an Ingress controller, Gateway API implementation, cloud load balancer, or platform-specific edge router.

Kubernetes also has objects for configuration and state. ConfigMaps hold non-secret configuration. Secrets hold sensitive values, though you still need careful access control and external secret management for strong production security. PersistentVolumes and PersistentVolumeClaims connect Pods to durable storage. These concepts matter because a Pod’s writable container layer is temporary, just like a Docker container’s writable layer: deleting or replacing the Pod loses data that was not stored in a volume or external service.

Syntax

Kubernetes is normally managed with kubectl. You can create objects directly, but most real workflows apply YAML manifests:

kubectl apply -f app.yaml
kubectl get pods
kubectl get deployments
kubectl get services
kubectl describe pod web-example
kubectl logs deployment/web
kubectl rollout status deployment/web
kubectl delete -f app.yaml
Object or command Purpose
Pod Runs one or more containers that share networking and optional volumes.
Deployment Maintains replicated Pods from a template and manages rolling updates.
ReplicaSet Lower-level object that keeps a specific number of matching Pods running; Deployments manage these for you.
Service Provides stable discovery and load distribution for a set of Pods selected by labels.
kubectl apply Creates or updates API objects to match the manifest.
kubectl get Lists objects and their current status.
kubectl describe Shows detailed object state, events, scheduling information, and troubleshooting clues.
kubectl logs Reads logs from a Pod or from Pods selected by a higher-level object.

Examples

Example 1: Build an Image for a Cluster

Kubernetes consumes images from registries. This Dockerfile creates a tiny static site image with a pinned base image tag, which keeps builds more reproducible than using nginx or latest.

FROM nginx:1.27-alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80

Output:

Image can be built as web-demo:1.0. EXPOSE records port metadata only; it does not publish a host port or create Kubernetes networking.

Build and tag the image before pushing it to the registry your cluster can pull from:

docker build -t web-demo:1.0 .
docker tag web-demo:1.0 registry.example.com/training/web-demo:1.0

Output:

[+] Building 1.2s (7/7) FINISHED
Successfully tagged web-demo:1.0
Successfully tagged registry.example.com/training/web-demo:1.0

The image layers are built locally. In a real cluster, you would also push the registry tag with docker push or use a local development cluster feature that imports images. Kubernetes nodes must be able to pull the referenced image, otherwise Pods can get stuck in an image pull error.

Example 2: A Deployment Keeps Pods Running

This manifest asks Kubernetes to keep three Nginx Pods running. The labels on the Pod template are important because other objects, such as Services, use them to find the Pods.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods -l app=web

Output:

deployment.apps/web created
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    3/3     3            3           20s
NAME                   READY   STATUS    RESTARTS   AGE
web-6d9f7b8d5b-4s2xm   1/1     Running   0          20s
web-6d9f7b8d5b-8kq7p   1/1     Running   0          20s
web-6d9f7b8d5b-rn6nw   1/1     Running   0          20s

You did not create three containers by hand. You declared a Deployment, the Deployment controller created a ReplicaSet, and the ReplicaSet created Pods. Each Pod runs a container from the pinned nginx:1.27-alpine image.

Example 3: A Service Gives Pods a Stable Name

Pods can be replaced and receive new IP addresses, so clients should not connect directly to individual Pod IPs. This Service selects Pods with app: web and exposes them inside the cluster on port 80.

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
    - name: http
      port: 80
      targetPort: 80
kubectl apply -f service.yaml
kubectl get services web
kubectl get endpoints web

Output:

service/web created
NAME   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
web    ClusterIP   10.96.120.55    <none>        80/TCP    8s
NAME   ENDPOINTS                                   AGE
web    10.244.1.7:80,10.244.2.9:80,10.244.3.4:80   8s

The Service has a stable name, web, even though the backing Pods can change. A ClusterIP Service is internal to the cluster. To receive traffic from outside the cluster, you need a different exposure path such as type: LoadBalancer on supported platforms or an Ingress controller.

Example 4: Roll Out a New Image

Changing a Deployment updates desired state. Kubernetes then moves the actual Pods toward that state.

kubectl set image deployment/web nginx=nginx:1.27.1-alpine
kubectl rollout status deployment/web
kubectl get pods -l app=web

Output:

deployment.apps/web image updated
Waiting for deployment "web" rollout to finish: 1 old replicas are pending termination...
deployment "web" successfully rolled out
NAME                   READY   STATUS    RESTARTS   AGE
web-7b8d65b79c-5zjxb   1/1     Running   0          28s
web-7b8d65b79c-f2g6p   1/1     Running   0          31s
web-7b8d65b79c-ks9dw   1/1     Running   0          34s

The old Pods are replaced by new Pods using the new image. If a rollout goes badly, kubectl rollout undo deployment/web can return to the previous ReplicaSet when the rollout history is available.

How It Works Step by Step

  1. You build an OCI image from read-only layers and publish it where cluster nodes can pull it.
  2. You submit YAML to the Kubernetes API with kubectl apply. The API server validates and stores the desired object state.
  3. The Deployment controller notices the desired Deployment and creates or updates a ReplicaSet.
  4. The ReplicaSet controller notices the desired replica count and creates missing Pods.
  5. The scheduler assigns unscheduled Pods to suitable nodes based on resources, constraints, and cluster state.
  6. The kubelet on each chosen node asks the container runtime to pull image layers, create containers, attach networking, mount volumes, and start processes.
  7. Service controllers and networking components maintain stable virtual networking for selected Pods.
  8. Controllers keep reconciling. If a Pod disappears, replacement work is scheduled until actual state matches desired state again.

Common Mistakes

Creating Pods Directly for Long-Running Apps

Wrong:

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
    - name: nginx
      image: nginx:1.27-alpine

A standalone Pod is useful for debugging and tiny experiments, but it does not give you rolling updates or a normal replica controller. Use a Deployment for stateless long-running services.

Assuming containerPort Publishes Traffic

containerPort in a Pod template is documentation and useful metadata, similar in spirit to Dockerfile EXPOSE. It does not publish a host port or make the app reachable from the internet. Use a Service, Ingress, Gateway, or platform load balancer for traffic.

Using latest in Manifests

Wrong:

containers:
  - name: api
    image: registry.example.com/training/api:latest

latest is a moving tag. A rollout today and a rollout next week can pull different contents while the manifest looks unchanged. Use tested version tags, and for strict production reproducibility pin images by digest.

Scaling Stateful Workloads Like Stateless Ones

Wrong:

kubectl scale deployment/postgres --replicas=3

That command asks for three PostgreSQL Pods, but it does not create database replication, backups, leader election, or safe shared storage. Stateful systems need purpose-built operators, StatefulSets, managed databases, or product-specific clustering instructions.

Best Practices

  • Use Docker or another OCI builder to produce small, pinned, repeatable images before deploying to Kubernetes.
  • Deploy long-running stateless services with Deployments, not naked Pods.
  • Use labels deliberately. Services, selectors, rollouts, and troubleshooting all depend on consistent labels.
  • Keep user traffic behind a Service plus an ingress or load-balancing layer; do not depend on Pod IPs.
  • Store durable data in PersistentVolumes or external managed services. Do not rely on a container or Pod writable layer.
  • Keep secrets out of Docker image layers and source-controlled manifests. Use Kubernetes Secrets carefully, restrict RBAC, and consider external secret stores.
  • Set resource requests and limits in real clusters so the scheduler has useful information and one workload cannot starve the node.
  • Use readiness and liveness probes for production services so Kubernetes knows when to route traffic and when to restart unhealthy containers.

Practice Exercises

  1. Write a Deployment manifest for nginx:1.27-alpine with two replicas and the label app: practice-web. Expected end state: kubectl get pods -l app=practice-web shows two running Pods.
  2. Add a ClusterIP Service that selects app: practice-web and exposes port 80. Hint: the Service selector must match the Pod template labels exactly.
  3. Change the image tag in the Deployment and watch the rollout. Expected end state: the old Pods are replaced by new Pods while the Deployment returns to an available state.

Summary

  • Kubernetes orchestrates containers by storing desired state and reconciling the cluster toward it.
  • Docker images still matter: Kubernetes nodes pull OCI image layers and run containers from them.
  • Pods are the smallest deployable unit, but Deployments are the normal object for replicated stateless apps.
  • Services provide stable discovery for disposable Pods whose IPs can change.
  • Rolling updates, self-healing, and scheduling are controller behaviors built around desired state.
  • Do not use latest, Pod IPs, or container writable layers as production foundations.