Kubernetes vs Docker: Different Jobs, One Team
A beginner-friendly guide to what each tool really does, how each one works on the inside, where they overlap, and how to choose between them. Every new word is explained the moment it appears.
Imagine you cook a wonderful lunch at home and pack it into a lunchbox. Anyone can open that box at any desk in any city and eat exactly the same lunch. Now imagine you are asked to feed five thousand children every day at a huge school. You would need many kitchens, many cooks, a schedule, a plan for when a cook falls sick, and someone to make sure nobody goes hungry. The lunchbox and the school cafeteria are both about food, but they solve very different problems.
That is the easiest way to remember the difference between Docker and Kubernetes. Docker helps you pack an application into a neat, portable box. Kubernetes helps you run thousands of those boxes across many computers without losing sleep. People often ask “Kubernetes or Docker?” as if they must pick one, but in most real companies the answer is “both, each doing its own job”. This guide walks through the whole story from the ground up, so that by the end you can explain it to a friend and choose sensibly for your own project.
AWhy Everyone Confuses Kubernetes and Docker
The two names appear side by side in job posts, tutorials, and conference talks, so it is natural to think they are rivals. They are not, and this chapter shows why.
Let us start with three plain definitions. A container is a small, sealed package that holds an application together with everything it needs to run, such as its code, its libraries, and its settings. Docker is the most famous set of tools for building and running such containers on a single computer. Kubernetes is a system that takes many containers and decides which computer should run each one, keeps them healthy, and connects them to each other and to the outside world. The word for that management job is orchestration, just like a conductor guiding an orchestra of musicians who each play their own instrument.
Docker is the lunchbox. It packs one meal so it stays fresh and can travel anywhere. Kubernetes is the school cafeteria manager. The manager does not cook your meal. The manager decides how many meals are needed, which kitchen prepares them, what happens when a cook is absent, and how every child receives the right plate on time.
Where the confusion comes from
There are three main reasons. First, the word “Docker” is used for many things. It is the name of a company, of a desktop application, of a background program called the Docker Engine, and loosely of the whole idea of containers. When someone says “we use Docker”, they might mean any of these.
Second, Docker once had its own built-in orchestrator called Docker Swarm. Swarm did a smaller version of what Kubernetes does, so for a few years the two really were competitors. Kubernetes won that race, and Swarm became a niche choice. The memory of that rivalry still lingers in many articles.
Third, in 2022 Kubernetes version 1.24 removed a small piece of code that let it talk to the Docker Engine directly. Headlines shouted that Kubernetes was “dropping Docker”, and many beginners panicked. In truth, almost nothing changed for everyday users, and we will explain exactly why in a later chapter.
Docker answers the question “how do I package and run one application?” Kubernetes answers the question “how do I run many applications reliably across many machines?” Different questions, different tools.
BContainers 101: The Building Block Both Tools Share
Before comparing the two tools, we must understand the one thing they both depend on: the container.
The “it works on my machine” problem
Every programmer has heard the sentence “but it works on my machine”. An application that runs perfectly on one laptop may crash on a server because the server has a different version of a library, a different setting, or a different operating system. Teams used to lose days chasing such differences. A container fixes this by carrying the application and its surroundings together, so the app sees the same world everywhere it goes.
Before 1956, loading a ship meant handling sacks, barrels, and crates of every shape by hand. Then Malcolm McLean popularised the standard steel shipping container. Cranes, trucks, trains, and ships all learned to handle one shape of box, no matter what was inside. Software containers do the same for programs. The box is standard, so every machine knows how to carry it, and nobody cares what is inside.
Containers versus virtual machines
You may have heard of virtual machines, or VMs. A virtual machine pretends to be a whole computer, including its own full operating system. That is powerful, but heavy. A single VM often needs several gigabytes of disk space and may take minutes to start. A container is lighter because it borrows the operating system core, called the kernel, from the machine it runs on. It only carries the application and its libraries. A very small base image such as Alpine Linux is only about 5 megabytes, and a container usually starts in a second or less.
flowchart TB
subgraph VMSIDE["Virtual Machines"]
direction TB
VH["Physical Server"] --> VHY["Hypervisor"]
VHY --> VA["Guest OS 1 + App 1"]
VHY --> VB["Guest OS 2 + App 2"]
end
subgraph CSIDE["Containers"]
direction TB
CH["Physical Server"] --> COS["Host Operating System Kernel"]
COS --> CR["Container Runtime"]
CR --> CA["App 1 + Libraries"]
CR --> CB["App 2 + Libraries"]
end
Because containers are light, one server can run dozens or even hundreds of them. That is why companies such as Netflix, Uber, and Spotify use them heavily: the same hardware serves more work at a lower cost.
Four words you will see everywhere
Image
A read-only template that holds the app and everything it needs. Think of it as a frozen meal kit that is ready to be heated.
Container
A running copy of an image. Start ten containers from one image and you get ten identical, separate running apps.
Registry
An online library where images are stored and shared. Docker Hub and Amazon Elastic Container Registry are well-known examples.
Host
The computer, real or virtual, that actually runs the containers. In Kubernetes, hosts are called nodes.
The difference between an image and a container is the same as the difference between a recipe card and a cooked dish. One recipe card can produce many dishes, and eating a dish does not change the card.
CWhat Docker Actually Is
Docker did not invent containers, but it made them easy enough for everyone to use. That ease is the reason it changed the industry.
A short history
Container ideas existed long before Docker. Unix systems had a feature called chroot in 1979, and Linux gained the building blocks of modern containers in the 2000s. But using them was hard and needed deep expert knowledge. In 2013 an engineer named Solomon Hykes showed Docker to the world at a Python conference. It came from a small company called dotCloud. Docker wrapped the difficult pieces in a friendly command line and a simple file format, and within a few years almost every software team was talking about it.
The main parts of Docker
Docker Engine
The core software installed on a machine. It contains a background program called the daemon that does the real work, plus a command-line tool that you type into.
Dockerfile
A plain text recipe that lists, step by step, how to build an image: start from this base, add these files, install these libraries, run this program.
Docker Image
The result of following the recipe. It is built in layers and can be copied to any machine that has a container runtime.
Registry
The place where finished images are uploaded and downloaded. Docker Hub is the public default. Companies often run private ones.
Docker Compose
A helper that starts several related containers together on one machine, such as a web app, a database, and a cache, using a single description file.
Docker Desktop
A friendly application for Windows and Mac laptops that bundles the engine, a graphical dashboard, and extras for developers.
The three basic moves: build, ship, run
Build
You write the recipe and Docker turns it into an image. Each step in the recipe becomes a layer, and unchanged layers are reused, so later builds are much faster.
Ship
You upload the image to a registry. Now any teammate, test server, or production machine can download the exact same package.
Run
Any machine with Docker downloads the image and starts a container from it. The app behaves the same as it did on the developer laptop.
The Dockerfile is a restaurant recipe, the image is the sealed meal kit made from it, the registry is the warehouse that stores meal kits, and the container is the hot dish being served at a table. You can always throw the dish away and cook a fresh one from the same kit.
Containers are disposable by design. When a container is removed, anything it saved inside itself is gone. Data that must survive, like a customer database, needs to live in a separate place called a volume, or in a managed database service outside the container.
DInside Docker: How a Container Really Runs
A container looks like magic, but it is built from a few clever features of the Linux operating system. Knowing them removes the mystery.
Here is the surprising truth: a container is not a tiny computer. It is just an ordinary program running on the host, wrapped in rules that limit what it can see and how much it can use. Two Linux features create those rules, and a third makes images efficient.
Namespaces: what the program can see
A namespace gives a program its own private view of part of the system. One namespace hides other programs so the container thinks it is the only thing running. Another gives it its own network address. Another gives it its own file system view and its own computer name. The program lives inside a small illusion of having a whole machine to itself.
Control groups: how much the program can use
A control group, usually shortened to cgroup, sets limits. It can say “this container may use at most half a processor and 512 megabytes of memory”. Without such limits, one greedy program could starve all its neighbours. Engineers at Google contributed the original cgroups feature to the Linux kernel in 2007, years before Docker existed. That is a hint about where Kubernetes ideas came from.
Layered file systems: how images stay small
A Docker image is made of stacked, read-only layers. When a container starts, Docker adds one thin writable layer on top. If ten containers use the same base layers, the computer stores those layers once and shares them. This saves disk space and makes downloads faster, because only missing layers need to travel over the network.
Picture an old classroom overhead projector with stacked transparent sheets. Each sheet adds some drawing, and together they form one picture. The bottom sheets never change. A student can scribble on the top sheet without damaging the ones underneath, and wiping the top sheet restores the original picture instantly.
Networking and storage for a single container
A container is sealed, so it needs deliberate doorways to talk to the world. Docker gives every container a private network address on a virtual network inside the host. To let visitors reach a web application, you publish a port, which means telling Docker “send traffic arriving at this number on the host to that number inside the container”. Containers placed on the same virtual network can also find each other by name, which is how a web container reaches its database container.
Storage works in a similar deliberate way. A volume is a folder managed by Docker that lives outside the container’s own layers. When the container is deleted, the volume stays, and a new container can attach to it and carry on where the old one stopped. A bind mount is a simpler cousin that connects a folder from the host directly into the container, which developers love because they can edit code on their laptop and see changes instantly inside the running app.
A container is like a hotel room with the door locked. The published port is the reception phone that guests outside can call, the private virtual network is the internal hotel telephone between rooms, and a volume is the hotel safe that keeps your valuables even after you check out and a new guest takes the room.
The chain of programs behind one command
When you type a Docker command, several programs cooperate. The command-line tool sends your request to the daemon. The daemon hands the job to a lower-level manager called containerd, which downloads images and tracks running containers. Containerd then calls runc, a tiny program that asks the kernel to create the namespaces and cgroups and start your application. Once the container is running, runc exits and the kernel keeps enforcing the rules.
flowchart LR
U["Developer runs Docker command"] --> CLI["Docker CLI"]
CLI --> D["Docker Daemon dockerd"]
D --> R["Registry such as Docker Hub"]
D --> C["containerd"]
C --> RC["runc"]
RC --> K["Linux Kernel"]
K --> NS["Namespaces: private view"]
K --> CG["Cgroups: resource limits"]
NS --> APP["Running Container"]
CG --> APP
Why images work everywhere: open standards
In 2015 the industry created the Open Container Initiative, or OCI, to write shared rules for how images and runtimes should behave. Because of OCI, an image built by Docker can be run by other tools such as containerd, CRI-O, or Podman. This portability is the hidden reason that the 2022 Kubernetes change did not break anyone’s images.
Linux namespaces and Kubernetes namespaces share a name but are different things. The Linux kind isolates what a process can see. The Kubernetes kind is just a way to group and separate objects inside a cluster, like folders. Keep them apart in your mind.
Containers need a Linux kernel. On a Mac or a Windows laptop, Docker Desktop quietly runs a small hidden Linux virtual machine and starts your containers inside it. On a Linux server there is no such extra layer.
EWhat Kubernetes Actually Is
Docker gets one container running. Kubernetes exists for the moment you have hundreds or thousands of them and a single human cannot keep track any more.
Where the name and the idea came from
The word Kubernetes comes from a Greek word meaning helmsman, the person who steers a ship. People often write it as K8s, because there are eight letters between the K and the s. Google created it, building on lessons from an internal system called Borg, which had been starting and managing Google’s own programs across huge fleets of machines for many years. Google announced Kubernetes in June 2014, released version 1.0 in July 2015, and handed it to a neutral home called the Cloud Native Computing Foundation, so that no single company controls it.
The problems it solves
Imagine your shop grows from one container to five hundred, spread over forty machines. Suddenly you face questions that Docker alone does not answer.
Where should it run?
Which of the forty machines has enough free memory and processor power for this new container? Kubernetes picks one automatically.
What if it crashes?
If a container dies or a whole machine breaks, something must start a replacement. Kubernetes does this without waking anybody up.
What if traffic doubles?
During a sale, you need more copies of the app, and afterwards fewer. Kubernetes can add and remove copies based on load.
How do parts find each other?
Containers come and go, and their addresses change. Kubernetes gives groups of them a stable name and spreads the traffic fairly.
How do I update safely?
Replacing every copy at once causes downtime. Kubernetes swaps them gradually and can roll back if the new version misbehaves.
Where do settings and passwords go?
Hard-coding them into images is dangerous. Kubernetes stores settings and secrets separately and delivers them to the right containers.
The big idea: you describe the goal, not the steps
With Kubernetes you do not give orders such as “start container A on machine 7”. Instead you write a description of the world you want, for example “I want three copies of my web app running, using this image, each with this much memory”. This description is called the desired state. Kubernetes constantly compares desired state with the actual state and fixes any difference. This repeating check-and-fix routine is called a control loop or reconciliation loop.
A home thermostat is a perfect example. You do not tell the heater when to switch on. You set the temperature you want, say 22 degrees, and the thermostat keeps checking the room and turning the heater on or off until reality matches your wish. Kubernetes is a thermostat for applications.
Kubernetes does not build images and it is not a container runtime itself. It relies on other tools to build images and on a runtime such as containerd to start containers. Kubernetes is the manager, not the worker.
FKubernetes Architecture: Control Plane and Worker Nodes
A Kubernetes installation is called a cluster. Every cluster has a thinking part and a working part, and knowing who does what makes everything else easier.
A cluster is a group of computers that act as one big machine. The computers that run your applications are called worker nodes. The computers that make decisions and keep records form the control plane. In small setups these can be the same machines, but in production they are usually separated.
Think of a restaurant chain. Head office decides the menu, keeps records, and sends instructions. Each branch kitchen has a local manager who follows the instructions, cooks the food, and reports back. The control plane is head office. The worker nodes are the branch kitchens, and the kubelet on each node is the local manager.
flowchart TB
USER["Engineer using kubectl or CI pipeline"] --> API
EXT["Users on the internet"] --> LB["Cloud Load Balancer"]
LB --> ING["Ingress Controller"]
subgraph CP["Control Plane"]
API["API Server"]
ETCD["etcd database"]
SCH["Scheduler"]
CM["Controller Manager"]
API ETCD
SCH --> API
CM --> API
end
subgraph N1["Worker Node 1"]
KL1["kubelet"]
KP1["kube-proxy"]
RT1["Container Runtime"]
P1["Pod A"]
P2["Pod B"]
KL1 --> RT1
RT1 --> P1
RT1 --> P2
end
subgraph N2["Worker Node 2"]
KL2["kubelet"]
KP2["kube-proxy"]
RT2["Container Runtime"]
P3["Pod C"]
KL2 --> RT2
RT2 --> P3
end
API --> KL1
API --> KL2
ING --> P1
ING --> P3
The parts, one by one
API Server
The front door. Every request, from engineers, tools, and internal parts, passes through it. It checks who you are and whether you are allowed to do the thing.
etcd
The cluster’s memory. A small, reliable database that stores every object and setting. It uses a voting method called Raft so that its copies agree with each other.
Scheduler
The matchmaker. It watches for new pods without a home and picks the best node using free resources, rules, and preferences.
Controller Manager
A bundle of control loops. One keeps the right number of copies, another handles failed nodes, another manages endpoints, and so on.
kubelet
The agent on every node. It receives assignments, tells the runtime to start containers, checks their health, and reports back to the API server.
kube-proxy
Keeps network rules on the node up to date so that traffic sent to a service name reaches one of the healthy pods behind it.
Container Runtime
The software that really pulls images and starts containers. Common choices are containerd and CRI-O.
DNS and Network Plugin
CoreDNS turns service names into addresses. A network plugin gives every pod its own address so pods can talk without tricks.
How pods talk to each other
Kubernetes follows one simple networking promise: every pod gets its own address, and every pod can reach every other pod without clever tricks, no matter which node each one lives on. The network plugin makes this promise true. Because pods are replaced often and their addresses change, other programs should never remember a pod’s address. They talk to a Service instead, which has a fixed name and address, and kube-proxy quietly forwards each request to one of the healthy pods behind it.
Traffic from the internet follows a slightly longer road. A cloud load balancer receives the visitor first and spreads visitors across nodes. An ingress controller, which is a web server that understands Kubernetes rules, then looks at the web address and decides which service should receive the request. You can think of it as the reception desk of a large building, sending each guest to the right office.
Think of a big company phone system. Employees change desks all the time, so nobody memorises personal numbers. Customers call the department number, and the switchboard routes the call to whoever is free and present. Services are the department numbers, and kube-proxy is the switchboard.
If etcd is lost with no backup, the cluster forgets everything it was supposed to run. Production clusters run three or five etcd copies, always an odd number so that a clear majority can always vote, and they take regular backups. Managed services like Amazon EKS run this part for you.
GKubernetes Objects You Must Know
In Kubernetes, everything you want is described as an object. A handful of objects cover most of daily life.
The pod: the smallest unit
Kubernetes does not run bare containers. It wraps one or more containers in a pod. The containers in a pod always land on the same node, share one network address, and can share storage. Most pods hold just one container, but a second helper container can sit next to it when the two must work as a pair.
A pod is like a small apartment shared by a few roommates. They have one street address, one front door, and a shared fridge. Visitors knock on the apartment, not on individual roommates. If the apartment is demolished, all roommates leave together.
Labels: stickers that hold everything together
A label is a small tag such as “app equals shop” that you stick on objects. Other objects then find their targets by asking for “everything with this sticker”. This loose connection is what lets a service find its pods even as pods are replaced.
The most important objects at a glance
| Object | Its job | Everyday comparison |
|---|---|---|
| Pod | Runs one or more tightly linked containers | A shared apartment |
| ReplicaSet | Keeps a fixed number of identical pods alive | A shift manager counting staff |
| Deployment | Manages ReplicaSets and handles smooth updates and rollbacks | A store manager who plans staff changes |
| Service | Gives a stable name and address to a changing set of pods | A restaurant’s single phone number |
| Ingress | Routes outside web traffic to the right service | A building’s reception desk |
| ConfigMap | Holds non-secret settings | A notice board of rules |
| Secret | Holds sensitive values such as passwords and tokens | A locked key cabinet |
| Namespace | Splits one cluster into separate areas | Floors in an office block |
| Volume and PersistentVolumeClaim | Provide storage that outlives a pod | A rented storage unit |
| StatefulSet | Runs pods that need stable names and their own storage | Numbered lockers assigned to named people |
| DaemonSet | Runs one pod on every node | A security guard at every entrance |
| Job and CronJob | Run tasks once or on a schedule | A one-off errand or a weekly chore |
| HorizontalPodAutoscaler | Adds or removes pods based on load | Opening extra checkout counters at rush hour |
Deployment and Service: the everyday pair
Most stateless web applications use just two objects together. A Deployment says “keep three copies of this image running and update them gently”. A Service says “give all pods with this label one steady name and share incoming traffic between them”. Users and other apps talk to the service name and never worry about which pod answers.
Applications that keep no important data inside themselves, called stateless, are the easiest to run on Kubernetes. Databases and other stateful programs are possible, but they need extra care. Many teams prefer a managed database service outside the cluster for that reason.
HData Flow and Lifecycle: From Code to Running App
Let us follow one application from the developer’s keyboard to a live service, first with Docker alone and then with Kubernetes added.
Path one: Docker on a single server
Write and package
The developer writes the app and a Dockerfile, then builds an image on a laptop or a build server.
Test locally
The developer starts a container from the image and checks that it behaves properly.
Push to a registry
The image is uploaded with a version tag so everyone can fetch the same package.
Run on the server
Someone logs in to the server, downloads the image, and starts the container. If it crashes, a restart policy may bring it back, but nothing more clever happens.
Path two: Kubernetes across a cluster
The first three steps are the same. The difference begins when the image is ready to run. Instead of logging in to servers, the engineer sends a description of the desired state to the cluster. Here is what happens inside, step by step.
sequenceDiagram
participant E as Engineer
participant A as API Server
participant D as etcd
participant C as Controllers
participant S as Scheduler
participant K as kubelet on Node
participant R as Container Runtime
E->>A: Submit Deployment with 3 replicas
A->>D: Save desired state
A-->>E: Accepted
C->>A: Notice Deployment, create ReplicaSet and 3 Pods
S->>A: Find Pods with no node, assign each to a node
K->>A: See Pods assigned to my node
K->>R: Pull image and start containers
R-->>K: Containers running
K->>A: Report Pod status Running
Note over K,A: Health probes keep checking every few seconds
Notice a beautiful detail: the parts of Kubernetes do not give commands to each other. Each one simply watches the API server for work that belongs to it, does that work, and writes the result back. This makes the system loosely coupled, so one part can crash and restart without confusing the others.
The life of a pod
A pod moves through a few simple phases. It starts as Pending while the scheduler finds a node and the images download. It becomes Running when at least one container has started. If it finishes its work successfully, as a batch job does, it becomes Succeeded. If a container fails and cannot be restarted, it becomes Failed. If the node stops talking to the control plane, the state is Unknown. Pods are treated as disposable: when one dies, Kubernetes does not repair it, it creates a fresh replacement.
Health checks and rolling updates
Kubernetes uses small tests called probes. A liveness probe asks “is this container stuck?” and triggers a restart if it fails. A readiness probe asks “is this container ready to receive visitors?” and keeps traffic away until the answer is yes. When you release a new version, a rolling update starts a few new pods, waits for them to become ready, and only then removes old ones. Users see no interruption. If the new pods never become ready, the update pauses, and you can roll back to the previous version with one action.
Scaling in action
Suppose an online shop normally needs four pods to serve its visitors, but on a festival sale day traffic jumps to ten times the usual amount. A HorizontalPodAutoscaler watches a number such as average processor use. When the number climbs above the target you set, it raises the desired count of pods, and the normal control loops create them. If the cluster runs out of room, a separate cluster autoscaler can ask the cloud provider for more nodes. When the sale ends and traffic falls, the same process runs in reverse, and you stop paying for unused machines.
With plain Docker, the same event would need a human to start extra containers, adjust a load balancer, and remember to shut everything down afterwards. That manual effort is exactly the pain that Kubernetes was created to remove. It is also why companies with sudden traffic spikes, such as ticketing, food delivery, and streaming services, value it so highly.
Without a readiness probe, Kubernetes assumes a pod is ready the instant its process starts. A slow-starting app would then receive visitors before it can answer, and users would see errors during every release.
IDocker vs Kubernetes Side by Side
Now that both tools are clear on their own, we can compare them fairly. The table below shows why they are teammates and not opponents.
| Question | Docker | Kubernetes |
|---|---|---|
| Main job | Build images and run containers | Manage many containers across many machines |
| Typical scope | One machine | A cluster of machines |
| Smallest unit | Container | Pod |
| Builds images? | Yes | No, it only runs them |
| Self-healing | Basic restart policies only | Replaces failed pods and moves work off broken nodes |
| Scaling | Manual, or scripted by you | Automatic scaling based on load |
| Load balancing | Limited, mostly by adding another tool | Built in through Services and Ingress |
| Rolling updates and rollback | Not built in for single-host use | Built in |
| Storage handling | Volumes on the host | Rich storage system that works across nodes |
| Learning curve | Gentle, a weekend to get started | Steep, months to feel comfortable |
| Best fit | Development, testing, small apps | Large or growing production systems |
Where Compose and Swarm fit
Docker Compose
Describes a small application made of several containers and starts them together. Perfect for laptops, demos, and small servers.
Docker Swarm
Docker’s own orchestrator. It is simpler than Kubernetes but has far fewer features and a much smaller community today.
Kubernetes
The industry standard for orchestration, with a huge ecosystem of tools, cloud services, and trained engineers.
Swarm’s decline was helped by business events. Docker announced support for Kubernetes in 2017, and in 2019 the company sold its enterprise business to Mirantis. Swarm mode still works and some small teams like its simplicity, but most new projects choose Kubernetes.
The famous “Kubernetes dropped Docker” story
Kubernetes talks to container runtimes through a standard plug-in interface called the Container Runtime Interface, or CRI. The Docker Engine was created before this interface existed and does not speak it. To keep supporting Docker, Kubernetes carried a special adapter named dockershim. Maintaining that adapter was a burden, so version 1.24, released in 2022, removed it.
But remember the chain from Chapter D: the Docker Engine itself uses containerd underneath. Kubernetes simply started talking to containerd directly and skipped the middle layer. Images built with Docker follow the OCI standard, so they run unchanged. What really changed is that you can no longer type Docker commands on a Kubernetes node to inspect containers, and you use CRI tools instead.
Kubernetes stopped needing the Docker Engine to run containers, but it still happily runs every image you build with Docker tools.
JAdvantages, Disadvantages and Trade-offs
Every tool gives something and takes something. Being honest about the costs is what separates a good decision from a fashionable one.
Docker
Advantages
- Easy to learn and quick to start using
- Removes the “works on my machine” problem
- Fast to build and start, thanks to layers and shared kernels
- Huge library of ready-made images
- Great for local development and automated testing
Disadvantages
- Does not manage groups of machines by itself
- Weaker isolation than virtual machines because the kernel is shared
- Limited self-healing and scaling on a single host
- Data inside containers is lost unless volumes are used
- A single host is a single point of failure
Kubernetes
Advantages
- Automatic recovery from crashes and machine failures
- Scales up and down with demand
- Safe rolling updates and quick rollbacks
- Works on any major cloud or your own data centre
- Very large ecosystem and community support
Disadvantages
- Steep learning curve with many new terms
- Operating the control plane yourself is hard work
- Can be overkill and expensive for small applications
- Complex networking and security settings that are easy to get wrong
- Frequent releases mean regular upgrade chores
Owning a bicycle is cheap, simple, and perfect for a trip across town. Running a bus company can carry thousands of people, but you need drivers, a depot, timetables, and mechanics. Nobody should start a bus company to ride to the corner shop, and nobody should run a big city on a single bicycle.
The trade-offs that matter most
Power against simplicity. Kubernetes gives you automation, but each feature is one more thing to learn, configure, and debug. Flexibility against lock-in. Kubernetes runs almost anywhere, which protects you from depending on one cloud, but a fully managed cloud service can be faster to operate. Efficiency against isolation. Sharing a kernel packs more work onto each machine, yet a serious flaw in the kernel or runtime could affect all containers on that machine. For highly sensitive work, teams add extra sandboxing or separate machines.
Notice also the hidden cost: people. A Kubernetes platform needs engineers who understand it. For a team of three people running one website, the time spent on cluster upkeep may be larger than the benefit.
Thinking about cost honestly
Cost has three parts. The first is infrastructure: the machines, storage, and network traffic. Containers help here because they pack more work onto each machine, and Kubernetes helps further by scheduling pods onto nodes that have room. The second is platform overhead: a Kubernetes cluster runs its own helper programs on every node, and managed services usually charge a small hourly fee for each control plane. The third and biggest is human time: learning, upgrades, incident handling, and security reviews.
A useful rule of thumb is to compare the cost of a mistake with the cost of prevention. If an hour of downtime would cost your business a lot of money or trust, then automatic recovery and safe releases are worth their price. If an hour of downtime on a quiet evening costs almost nothing, a simpler setup is the wiser purchase.
KSecurity in Docker and Kubernetes
Containers make delivery fast, but they also make it easy to ship a mistake to thousands of machines at once. Security must be planned in layers.
Think of a large apartment building. The main gate checks visitors, each flat has its own lock, cameras watch the corridors, and the caretaker keeps a list of who may enter which floor. No single lock is trusted alone. Container security also relies on many small protections stacked together.
Docker-level protection
Trust your base
Start from small, well-known official images, scan them for known flaws, and rebuild often. Fewer packages inside means fewer holes to attack.
Do not run as root
By default a process inside a container may run as the all-powerful root user. Create a normal user in the image so a break-in has less power.
Guard the Docker socket
The Docker daemon usually runs with high privileges. Anyone who can talk to its control socket can effectively control the whole host. Never expose it carelessly.
Limit abilities
Drop unneeded Linux capabilities, use a read-only file system where possible, and apply built-in filters such as seccomp that block dangerous system calls.
Kubernetes-level protection
RBAC
Role-Based Access Control decides who may do what. Give each person and each program only the permissions it truly needs, and nothing more.
Network Policies
By default, any pod can talk to any other pod. Network policies act like internal walls so that, for example, only the web tier may contact the database.
Pod Security Standards
Three levels, called privileged, baseline, and restricted, describe how risky a pod’s settings may be. Production workloads should aim for restricted.
Protect stored secrets
Kubernetes Secrets are only encoded, not encrypted, unless you turn on encryption at rest. Many teams keep the real secrets in a vault service such as AWS Secrets Manager.
Lessons from real incidents
In 2018, security researchers found that an administration console for a Kubernetes cluster at Tesla was reachable from the internet with no password. Attackers had used it to run hidden cryptocurrency mining inside the company’s cloud account. The lesson is simple and timeless: never leave management doors open to the public internet, and always require strong login. In 2019 a flaw in runc, the small program from Chapter D, allowed a malicious container to break out to the host on unpatched systems. The lesson: keep runtimes and nodes updated, because a shared kernel means bugs in the shared layer matter to everyone.
An image can be copied and inspected by anyone who can pull it. A password placed in the image lives in its layers forever, even if a later step deletes it. Provide secrets at run time from a secure store instead.
Keep the Kubernetes API server private wherever possible, or limit which network addresses may reach it. Turn on audit logs so you can see who did what and when.
LMonitoring, Logging and Metrics
Containers appear and vanish quickly, so you cannot log in and look around after a problem. You must record what happens as it happens.
A car has a dashboard that shows speed and fuel right now, which are its metrics. An aircraft has a black box that records everything for later study, which are its logs. A tracking system that follows a parcel through every depot is like tracing. A healthy system needs all three.
The three pillars
Metrics
Counts and measurements over time, such as processor use, memory use, requests per second, and error rate. They tell you that something is wrong.
Logs
Time-stamped messages written by your programs. They tell you what happened and often why.
Traces
A record of one request as it travels through many services. They tell you where the time was spent.
Monitoring with Docker
A healthy container writes its messages to standard output and standard error, and Docker collects them. You can read them with the logs command and see live processor and memory use with the stats command. Docker also supports health checks, which mark a container as healthy or unhealthy. For a single server this is often enough. For many servers you need a central place to gather everything.
Monitoring with Kubernetes
Kubernetes has no complete monitoring system built in, but it provides hooks for a rich ecosystem. A small add-on called metrics-server supplies basic processor and memory numbers and powers automatic scaling. kube-state-metrics reports the state of objects, such as how many pods are ready. Prometheus collects and stores metrics, Grafana draws dashboards, and Alertmanager sends messages to people when something crosses a limit. For logs, a small agent such as Fluent Bit runs on every node, reads container output, and forwards it to a search system like OpenSearch or Amazon CloudWatch. For traces, teams commonly use OpenTelemetry.
flowchart LR
P["Pods write logs and expose metrics"] --> FB["Log agent on each node"]
P --> PR["Prometheus collects metrics"]
P --> OT["OpenTelemetry collector for traces"]
FB --> LS["Central log store"]
PR --> GF["Grafana dashboards"]
PR --> AM["Alertmanager"]
OT --> TS["Trace viewer"]
AM --> ON["On-call engineer"]
LS --> ENG["Engineers searching logs"]
GF --> ENG
TS --> ENG
What to watch first
Google’s engineers, in their well-known reliability book, suggest four golden signals that suit almost any service. They are latency, which is how long requests take; traffic, which is how many requests arrive; errors, which is how many requests fail; and saturation, which is how full your resources are. In Kubernetes also watch pod restarts, pods stuck in Pending, and nodes that are running out of memory or disk space.
Because pods are disposable, do not write log files inside a container. Print messages to standard output and let the platform collect them. The logs then survive even after the pod is gone.
MDesign Patterns and Anti-Patterns
Engineers have discovered reliable shapes for container applications, and also some tempting shapes that cause trouble.
Patterns that work well
One job per container
Each container should run one main program. This makes updates, scaling, and debugging much simpler than a container that hides many programs.
Sidecar
A helper container runs beside the main one to add a feature, such as shipping logs or handling secure connections. Service meshes like Istio use sidecar proxies based on Envoy, a tool first built at Lyft.
Init container
A short task that must finish before the main container starts, for example waiting until a database is reachable or preparing files.
Ambassador and adapter
An ambassador hides the messy details of talking to outside systems. An adapter converts output into a format that other tools expect.
Rolling, blue-green, canary
Rolling replaces pods gradually. Blue-green keeps two full environments and switches traffic at once. Canary sends a tiny share of users to the new version first.
Operator
A custom controller that teaches Kubernetes to manage a complex program, like a database, using the same desired-state idea.
A canary release is named after the canary birds that miners once carried underground. If the bird was fine, the air was safe. Sending a small group of users to the new version first works the same way: if they stay healthy, everyone else can follow.
Anti-patterns to avoid
What it is
The fat container: putting the web server, the database, and several helper programs into one container to keep things “simple”.
Why it hurts
You cannot scale one part without scaling all of them, one crash takes everything down, and every update rebuilds the entire bundle.
Better approach
Give each program its own container and connect them through a network or, in Kubernetes, through pods and services.
What it is
Using the moving tag called latest for production images.
Why it hurts
The word latest points to whatever was uploaded most recently. Two servers may pull different versions at different times, and a rollback becomes guesswork.
Better approach
Use exact version tags, or even the image’s unique fingerprint called a digest, so that every machine runs precisely the same package.
What it is
Premature orchestration: setting up a full Kubernetes cluster for one small application with a handful of users.
Why it hurts
You pay for the complexity of upgrades, security, and networking long before you receive the benefits of scale.
Better approach
Begin with Docker and Compose on a single server or a managed container service, and move to Kubernetes when real needs appear.
What it is
Keeping important data inside a container’s own writable layer or on a single pod’s local disk.
Why it hurts
The moment the container is replaced, the data is gone. This is the most common cause of surprise data loss for beginners.
Better approach
Store data in volumes, persistent storage claims, or managed databases that live independently of any container.
NBest Practices and Common Mistakes
These habits come from years of painful lessons in real production systems. Adopt them early and you skip most of the pain.
Good habits for Docker images and containers
Keep images small
Choose a minimal base image and remove tools you do not need at run time. Smaller images download faster, start faster, and expose fewer weaknesses.
Build in stages
Use one stage to compile your program with heavy tools, then copy only the finished result into a clean final image. The heavy tools never reach production.
Order the recipe wisely
Put steps that rarely change, like installing libraries, near the top, and steps that change often, like copying your code, near the bottom. Docker then reuses cached layers and builds in seconds.
Pin versions
Name exact versions for base images and libraries so that a build today matches a build next month.
Run as a normal user and add a health check
Reduce power and make problems visible from the very first day.
Good habits for Kubernetes
Set requests and limits
A request tells the scheduler how much a pod needs. A limit stops it taking too much. Without them, one busy pod can starve its neighbours.
Always add probes
Use readiness probes so traffic only reaches ready pods, and liveness probes so stuck pods restart.
Run several copies in several zones
Two or more replicas spread across different data-centre zones keep the service alive when one zone has trouble.
Use disruption budgets
A PodDisruptionBudget tells Kubernetes the minimum number of pods that must stay up during maintenance, so upgrades never remove everything at once.
Keep desired state in version control
Store your descriptions in a Git repository and apply them through automation. This practice, called GitOps, gives you history, reviews, and easy rollbacks.
Right-size and autoscale
Review real usage regularly. Clusters often run at a small fraction of their capacity, and that idle space is money wasted.
Common mistakes and how to fix them
| Mistake | What happens | Fix |
|---|---|---|
| No memory limit set | A leaky app eats the whole node and neighbours crash | Set requests and limits based on measured use |
| Memory limit set far too low | The pod is killed again and again with an out-of-memory status | Measure real usage, then add sensible headroom |
| Only one replica | Any restart or node failure causes downtime | Run at least two or three replicas |
| No readiness probe | Users receive errors during every release | Add a probe that checks the app is truly ready |
| Secrets inside images | Anyone with the image can read them | Inject them at run time from a secure store |
| Ignoring etcd backups | A control-plane failure loses all cluster records | Use a managed service or schedule and test backups |
| Skipping upgrades | Old versions lose security fixes and upgrades become a huge jump | Upgrade one version step at a regular rhythm |
| Too many tiny clusters | Every cluster needs care, so effort and cost multiply | Use namespaces and policies to share clusters safely |
Failure scenarios and how each tool reacts
Good engineers plan for failure before it arrives. Consider three common events. If a single container crashes, Docker with a restart policy will start it again on the same machine, and Kubernetes will create a replacement pod, possibly on a different node. If a whole machine dies, Docker has no answer beyond a person noticing and acting, while Kubernetes notices that the node stopped reporting, waits a short grace period, and recreates its pods on healthy nodes. If a bad release is deployed, Docker offers no built-in memory of the previous version, while a Kubernetes Deployment keeps a history and can return to the last good version quickly.
These differences explain why teams practise failure on purpose. Netflix made this famous with its Chaos Monkey tool, which randomly shuts down servers during working hours to prove that the system survives. The same spirit works well on a Kubernetes cluster: delete a pod, drain a node, and watch that users notice nothing.
Learn Docker first, then Kubernetes. Docker teaches you images, containers, networking, and volumes in a small, friendly setting. Kubernetes then feels like the same ideas at a larger scale, instead of a wall of unfamiliar words.
OReal-World Examples and How to Choose
Theory is useful, but seeing how real companies think makes the choice clearer.
How well-known organisations use these tools
Google: the origin story
Google ran its own services in containers for many years using Borg long before Docker became popular. Kubernetes carried those lessons to the public, and Google now offers it as a managed product called Google Kubernetes Engine.
Niantic and Pokémon GO: surviving a surprise
When Pokémon GO launched in 2016, it ran on Google’s cloud with Kubernetes. Player numbers rose far above the company’s own forecasts, and the ability to add capacity quickly helped the game keep running through the rush.
Spotify: moving from a home-made tool
Spotify first built its own orchestrator called Helios, then moved its services to Kubernetes so it could use the shared ecosystem instead of maintaining a custom system.
Airbnb: many teams, one platform
Airbnb has written publicly about moving its services onto Kubernetes so hundreds of engineers can deploy and scale independently on a shared, consistent platform.
Netflix: proof that there is more than one road
Netflix built its own container platform, called Titus, to match its very particular needs. Not every giant follows the crowd, but it also shows that big companies invest heavily in some form of orchestration.
Amazon: a menu of choices
On AWS you can use Amazon ECS, which is Amazon’s own simpler orchestrator, or Amazon EKS, which is managed Kubernetes. Both can run on AWS Fargate, a mode where Amazon manages the underlying servers so you only think about containers.
A small agency or startup: Docker on one server
A five-person team that runs a website, an API, and a database often does perfectly well with Docker Compose on one or two servers. Keeping it simple lets them spend time on customers rather than cluster upkeep.
A simple way to decide
flowchart TD
S["Start: I have an application"] --> Q1{"Do I need it to run the same everywhere?"}
Q1 -->|"Yes"| D["Package it with Docker"]
Q1 -->|"No"| STOP["Plain servers may be enough for now"]
D --> Q2{"More than a few services or servers?"}
Q2 -->|"No"| C["Docker Compose on one server or a simple managed container service"]
Q2 -->|"Yes"| Q3{"Need auto-scaling, self-healing, zero-downtime updates?"}
Q3 -->|"Yes"| Q4{"Do I have a platform team?"}
Q3 -->|"No"| C
Q4 -->|"Yes"| K["Kubernetes, self-managed or managed"]
Q4 -->|"No"| M["Managed Kubernetes such as EKS, GKE, AKS, or ECS with Fargate"]
| Your situation | Sensible starting point |
|---|---|
| Learning, building a prototype, or working alone | Docker and Docker Compose on your laptop |
| Small production app with steady traffic | Docker on one or two servers, or a simple managed container service |
| Growing product with many services and spiky traffic | Managed Kubernetes, for example Amazon EKS |
| Large company with many teams and strict rules | Kubernetes with a platform team, policies, and GitOps |
| Need to run in several clouds or on your own hardware | Kubernetes, because it looks the same nearly everywhere |
If you choose Kubernetes, let a cloud provider run the control plane. Managed offerings such as Amazon EKS, Google GKE, and Azure AKS handle the hardest parts, like etcd and upgrades of the control plane, so your team can focus on applications.
PFrequently Asked Questions
Short, plain answers to the questions beginners ask most.
QSummary and Key Takeaways
Let us close the loop with the lunchbox and the cafeteria one more time.
Docker made packaging simple. It taught the world to put an application and its surroundings into one portable box and to move that box anywhere. Kubernetes then solved the next problem: when there are thousands of boxes and hundreds of machines, someone must place them, watch them, replace the broken ones, connect them, and update them without stopping the service. The two tools meet at the container image, which is the standard box they both understand. Choosing between them is rarely an either-or decision. It is a question of timing, and of how much complexity your project can honestly justify.
Key Takeaways
- Different jobs: Docker builds and runs containers on a machine, while Kubernetes orchestrates containers across a whole cluster of machines.
- Shared foundation: Both rest on Linux namespaces, cgroups, layered images, and the Open Container Initiative standards, which is why Docker-built images run on Kubernetes.
- Desired state: Kubernetes works like a thermostat. You describe what you want, and its control loops keep fixing reality until it matches.
- The 2022 change: Removing dockershim in Kubernetes 1.24 only removed the middle layer. Docker-built images still run everywhere.
- Start simple: Begin with Docker and Compose, and adopt Kubernetes when you truly need auto-scaling, self-healing, and zero-downtime releases.
- Security in layers: Use small trusted images, non-root users, RBAC, network policies, encrypted secrets, and regular updates.
- Lean on managed services: If you choose Kubernetes, let a provider such as Amazon EKS run the control plane and spend your energy on your applications.