Docker is a pre-requisite before you proceed to understand kubernetes
Kubernetes (popularly known as k8s) is a container orchestration engine, which as the name suggests lets you create, delete, and update containers.
Note: Next.js can also be deployed horizontally scaled behind a load balancer, exactly like the Backend service shown above!
Your frontend, backend are all pods in your kubernetes cluster
In kubernetes, you can create and connect various machines together, all of which are running kubernetes. Every machine here is known as a node.
There are two types of nodes
The node that takes care of deploying the containers/healing them/listening to the developer to understand what to deploy
Consistent and highly-available key value store used as Kubernetes' backing store for all cluster data. Ref - https://etcd.io/docs/v3.5/quickstart/
Control plane component that watches for newly created Pods with no assigned node, and selects a node for them to run on. Its responsible for pod placement and deciding which pod goes on which node.
Ref - https://kubernetes.io/docs/concepts/architecture/controller/
The kube-controller-manager is a component of the Kubernetes control plane that runs a set of controllers. Each controller is responsible for managing a specific aspect of the cluster's state.
There are many different types of controllers. Some examples of them are:
An agent that runs on each node in the cluster. It makes sure that containers are running in a Pod.
The kube-proxy is a network proxy that runs on each node in a Kubernetes cluster. It is responsible for you being able to talk to a pod
In a Kubernetes worker node, the container runtime is the software responsible for running containers.
It interacts with the kubelet, which is the agent running on each node, to manage the lifecycle of containers as specified by Kubernetes pod specifications. The container runtime ensures that the necessary containers are started, stopped, and managed correctly on the worker node.
Common Container Runtimes for KubernetesThe Container Runtime Interface (CRI) is a plugin interface that allows the kubelet to use a variety of container runtimes without needing to know the specifics of each runtime. This abstraction layer enables Kubernetes to support multiple container runtimes, providing flexibility and choice to users.
A bunch of worker nodes + master nodes make up your kubernetes cluster. You can always add more / remove nodes from a cluster.
A Docker image is a lightweight, standalone, and executable software package that includes everything needed to run a piece of software, including the code, runtime, libraries, environment variables, and configuration files. Images are built from a set of instructions defined in a file called a Dockerfile.
A container is an image in execution. For example if you run
A pod is the smallest and simplest unit in the Kubernetes object model that you can create or deploy
You might wonder: "If the worker node has a container runtime, why doesn't Kubernetes just run the container directly? Why do we need this extra wrapper called a Pod?"
A container:
But Kubernetes needs more than just docker run my-backend. It needs:
A single container object cannot handle all that cleanly.
Pod is the smallest deployable unit in Kubernetes.
When you say:
replicas: 3Create 3 Pods
NOT
Create 3 containers
Why? Because Kubernetes schedules Pods to nodes — not containers.
Each Pod gets:
Its own IPIts own network namespace⚠️ Scheduled directly:
🚀 With Pods:
This simplifies:
Imagine these containers:
These must:
You cannot attach multiple containers directly at node level and expect this behavior cleanly.
Pod gives you: One logical application unit
❓ If Kubernetes ran containers directly:
✨ Pod solves this:
Kubernetes scheduler behavior:
Why?
Because a Pod defines the full workload definition:
A container alone is incomplete.
Think like this:
HR assigns teams to offices, not individual employees randomly.
Kubernetes is NOT a container manager.
It is a Pod orchestrator.
Containers are just an implementation detail.
Yes, BUT only if they use different ports!
Inside a single Pod, all containers share the same Network Namespace. This means they share the same IP address and the same localhost.
Think of a Pod like your localhost (Laptop/PC). If you try to run two apps on port 3000 on your laptop, the second one will crash with a "Port already in use" error.
The same thing happens in a Pod. If Container A listens on port 8080, Container B cannot listen on port 8080. It must use a different port (e.g., 9090).
Different ports = Happy Neighbors!
App A can talk to App B via localhost:4000
Same port = Crash!
Just like running two servers on port 3000 on your Mac.