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
- You build an OCI image from read-only layers and publish it where cluster nodes can pull it.
- You submit YAML to the Kubernetes API with
kubectl apply. The API server validates and stores the desired object state. - The Deployment controller notices the desired Deployment and creates or updates a ReplicaSet.
- The ReplicaSet controller notices the desired replica count and creates missing Pods.
- The scheduler assigns unscheduled Pods to suitable nodes based on resources, constraints, and cluster state.
- The kubelet on each chosen node asks the container runtime to pull image layers, create containers, attach networking, mount volumes, and start processes.
- Service controllers and networking components maintain stable virtual networking for selected Pods.
- 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
- Write a Deployment manifest for
nginx:1.27-alpinewith two replicas and the labelapp: practice-web. Expected end state:kubectl get pods -l app=practice-webshows two running Pods. - Add a ClusterIP Service that selects
app: practice-weband exposes port80. Hint: the Service selector must match the Pod template labels exactly. - 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.
