A Docker container is a process running on the host’s own Linux kernel, kept separate from everything else on the machine. It carries its code, runtime and dependencies along, which is why it behaves the same wherever it lands.
Docker Engine, containerd and runc handle the separation with Linux namespaces and control groups. There is no guest operating system and no emulated hardware involved.
The Linux Foundation’s Open Container Initiative published version 1.0 of its runtime and image specifications in July 2017. Thanks to that standard, an image built with Docker runs unmodified under other OCI-compliant engines.
What Is a Docker Container?

The easiest way to get it wrong is to picture a tiny virtual machine. A container never boots a kernel of its own. It borrows the one already running on the host, and that’s the whole trick.
Docker didn’t invent any of the underlying pieces. Namespaces and cgroups sat in the Linux kernel for years before the company existed. What Docker did was wrap them in tooling ordinary developers could use without reading kernel docs. The Docker platform bundles the engine, the command line client and the image format, and most teams just take the whole thing by default.
Two smaller tools sit underneath. containerd manages the container lifecycle, and runc does the low level work of spawning the isolated process according to the Open Container Initiative specification.
The payoff is that you package an application once and run it unchanged on a laptop, a CI runner or a production cluster. There’s no second operating system to patch or license. A container starts like any other process, without a boot sequence, and it shares the host kernel with every other container on the box.
That last part is also the catch. Isolation is real, but it happens at the process level, not the hardware level. More on that further down.
Docker Container vs Docker Image: What Is the Difference?

An image is the static template. Run it, and what you get is a container.
One image can spawn as many running containers as memory allows. Each container gets its own writable layer stacked on top of the same shared, read only image layers.
Images come from a Dockerfile, where every RUN, COPY and ADD instruction adds a layer. A multi-stage build throws away the build tools before the final image ships. The result gets a tag (nginx:1.27, for example) and is pushed to a registry.
Docker Hub is the default public registry for that push, though private registries and cloud provider registries behave the same way. Docker reports that Docker Hub offers more than 15 million images, which together are pulled more than 16 billion times per month (Docker, 2023).
Pulling an image copies its layers locally once. Start a second container, or a tenth, from that same image and those layers get reused instead of duplicated.
The image is read only and versioned by tag. The container is a running process with a writable layer on top. Delete the container and that layer goes with it, while the image stays untouched in local storage or in the registry.
Docker Container vs Virtual Machine: What Is the Difference?
A virtual machine emulates whole hardware and boots a full guest operating system on top of a hypervisor. A container skips all that, shares the host kernel and isolates a single process.
Nearly every practical gap between the two traces back to that one choice.
| Attribute | Docker container | Virtual machine |
|---|---|---|
| Kernel | Shared with host | Own guest kernel |
| Startup time | Milliseconds to seconds | Seconds to minutes |
| Isolation level | Process level | Hardware level |
| Typical density per host | 100+ | 10 to 15 |
A virtual machine still earns its place wherever full operating system isolation is a hard requirement.
Northflank’s 2026 numbers say containers start in milliseconds, while a full virtual machine boot takes seconds to minutes (Northflank, 2026). Lightweight microVMs such as Firecracker land in between at roughly 125 milliseconds. On density, a 128GB host commonly runs 100 to 200 containers, against 10 to 15 full virtual machines at similar memory limits.
PayPal shows what that density looks like in practice. The company has migrated more than 700 applications to Docker and has reported running over 200,000 containers (Mirantis case study). Matching that with individual virtual machines would take a far bigger fleet.
None of this makes virtual machines obsolete. They solve a different isolation problem, and choosing between the two comes down to how much of a boundary the workload actually needs.
For the adoption and usage numbers behind these figures, there’s a breakdown of Docker statistics worth a look.
How Does Isolation Work Inside a Docker Container?

Isolation comes from the Linux kernel, not from Docker. Namespaces, control groups and a union filesystem do the work together, and Docker packages them into something you can use without kernel level expertise.
The general technique is usually called containerization, and Docker happens to be the most common way developers put it into practice.
Namespaces
Namespaces decide what a process is allowed to see. The PID namespace gives the container its own process tree, which starts at PID 1. The network namespace hands it separate interfaces, routes and ports, and the mount namespace gives it its own view of the filesystem. Even the hostname gets its own namespace (UTS).
A process inside the container can’t see, signal or kill anything outside its namespace, even though both share one physical kernel.
Control Groups
Control groups, cgroups for short, cap how much CPU, memory and disk I/O a single container can use.
CPU shares limit processor time when there’s contention. Cross a memory limit and the kernel kills the process, not Docker. Block I/O limits throttle disk reads and writes per container.
Skip these caps and one runaway process can starve every other container on the host. Nobody enjoys debugging that at 2am.
Union Filesystem
Docker builds a container’s filesystem from stacked, read only image layers with one thin writable layer on top, unique to that container. OverlayFS is the driver most current installations use by default.
| Layer type | Owned by | Survives container removal |
|---|---|---|
| Image layers | The image | Yes |
| Writable layer | The container | No |
Removing the container deletes only that top layer. Everything underneath stays exactly as it was, ready for the next container built from the same image.
Docker Container Lifecycle States
Docker reports seven statuses for a container: created, running, paused, restarting, exited, removing and dead.
Most transitions come from a specific command. A container also moves to exited by itself when its main process finishes or crashes.
| State | Triggered by | Process running |
|---|---|---|
| Created | docker create | No |
| Running | docker start / docker run | Yes |
| Paused | docker pause | Frozen, not killed |
| Restarting | A restart policy after the container exits | Being started again |
| Exited | docker stop, or the main process ending | No |
| Removed | docker rm | Container no longer exists |
The last two statuses turn up less often. Removing shows while a container is being deleted. Dead marks one that was only partly removed and can’t be restarted anymore, only removed.
Stopping a container doesn’t delete it. A stopped container keeps its writable layer and its configuration on disk until something explicitly removes it.
Restart policies decide what happens after a crash when nobody is watching the terminal. The default is no, which never restarts anything automatically. With on-failure, Docker restarts the container only if the exit code signals an error. The always policy restarts it however it stopped, host reboot included, and unless-stopped does the same except that it respects a manual stop.
A container restarted by policy is still the same container. Its ID and its writable layer carry over, and it gets started again rather than rebuilt. That’s worth remembering when you restart a Docker container after a failure.
The Warehouse Group, a retail group that rebuilt its developer platform around Docker, cut the time to deploy a new development environment from weeks to about 60 seconds (Docker, 2025).
A jump like that usually comes from this lifecycle model. Spinning up a fresh container from an existing image skips the manual provisioning that a new virtual machine, or a new physical box, would need.
Docker Container Networking Modes

Docker puts each container in a network mode, and the choice changes both what the container can reach and what can reach it.
Bridge is the default. The container gets its own virtual network interface behind Docker’s internal bridge, which makes it the safe pick for a single host running several unrelated containers.
Host mode drops the port mapping layer and lets the container share the host’s network stack directly. You get raw network performance and give up isolation in exchange.
None means no networking at all, for workloads that only touch local disk or standard input and output.
Overlay spans multiple Docker hosts. Swarm and similar multi host setups use it so containers on different machines can talk as if they shared a subnet, and it’s what makes a multi node cluster behave like one network.
Port mapping is what makes bridge mode usable from outside the host. Publish container port 5000 to host port 8080 and outside traffic goes straight into the container’s isolated network namespace.
Pick the wrong mode and the symptom is nearly always the same. The service answers fine from inside the container and refuses every connection from anywhere else.
Docker Container Storage and Data Persistence
Anything a container writes lands in its own writable layer by default, and that layer vanishes the moment the container is removed.
Docker offers three ways around that. Named volumes are managed by Docker itself and are the recommended option for anything a database or application needs to keep. Bind mounts map a specific host folder straight into the container. Tmpfs mounts keep data in memory only, never touching disk, and it disappears on stop.
Named volumes are the closest thing containers have to a persistent, portable disk. Docker decides exactly where a named volume lives on the host, so the container never needs to know the underlying path.
Bind mounts skip that abstraction, which makes them handy for local development, where live code changes need to show up inside the container instantly.
The convenience has a cost, though. A bind mount ties the container to whatever exists at that exact host path, and that’s the kind of environment dependency containers are supposed to remove.
Tmpfs sits at the other end. It’s fast and ephemeral, and it suits caches and secrets that shouldn’t ever be written to disk.
What Are the Benefits and Limitations of Docker Containers?

Containers cut environment inconsistency, speed up deployment and let more workloads share the same hardware. They aren’t a universal upgrade, and the downsides matter as much as the wins.
On the plus side, the runtime stays consistent from a developer laptop through CI to production. Startup is faster and density is higher than with virtual machines on the same host. Deployable units get smaller, which suits a microservices architecture pattern well. Images are version controlled, so a rollback means pulling an older tag.
The downsides are real too. A shared kernel means no cross-OS isolation, so a Linux image won’t run natively on a Windows kernel. A container isn’t a hardened security boundary against untrusted, hostile code. And stateful workloads need extra care, because the container itself stays disposable.
Ataccama moved its infrastructure to Docker and reported a 75% faster deployment time alongside a 40% cut in the number of servers required (Docker, 2025).
Faster releases on fewer machines is the argument most teams actually make when they pick containers over a fleet of individual virtual machines.
It shows up most clearly in microservices architecture, where dozens of small, independently deployed services benefit from a unit that starts in milliseconds rather than minutes.
Docker Container Security: Controls and Practices

Docker isolates a container with the Linux kernel’s own security primitives, then adds narrower controls on top.
Seccomp filters which system calls a container may make. Docker’s default profile blocks around 44 of the more than 300 Linux system calls, the ones a typical application never needs.
AppArmor and SELinux confine what a container’s process can touch on the host, even if that process gets compromised. Linux capabilities strip root down to a named set of privileges instead of handing the container full administrative power.
Rootless mode goes further and runs the Docker daemon itself without root privileges. That shuts off a whole class of host takeover if the daemon is ever exploited.
Teams running this stack at scale know the concern isn’t theoretical. 89% of organizations experienced at least one container or Kubernetes related security incident in the past 12 months (Red Hat, 2024), and 67% delayed or slowed a deployment specifically over security concerns (Red Hat, 2024).
None of these controls make a container equal to a virtual machine’s isolation. They shrink the attack surface a shared kernel exposes. They don’t remove it.
Docker Container Orchestration: Compose, Swarm, and Kubernetes
A handful of containers can be managed by hand. Hundreds spread across dozens of hosts can’t, and that’s the gap orchestration tools fill.
| Tool | Scope | Best fit |
|---|---|---|
| Docker Compose | Single host, multi-container apps | Local development, small deployments |
| Docker Swarm | Native Docker clustering | Small to mid-size clusters |
| Kubernetes | Cluster-wide scheduling and scaling | Large, production-grade fleets |
Docker Compose describes a multi-container application in a single YAML file and starts and networks every service with one command.
Swarm turns a group of Docker hosts into one logical cluster. It uses the same CLI and the same OCI-compliant runtime underneath, so there’s very little new to learn.
Kubernetes works at a different scale altogether. It schedules containers across nodes, restarts failed ones and shifts workloads off hardware that goes down.
Production adoption reflects that. 82% of container users now run Kubernetes in production, up from 66% in 2023 (CNCF, 2026).
Comparing Kubernetes and Docker is really comparing an orchestrator with the container runtime it schedules. They aren’t two rival ways of doing the same job.
Most teams don’t pick one tool for life. Compose covers local development, then Swarm or Kubernetes takes over when the same containers move into production.
How to Run a Docker Container

The sequence is short and stays the same whatever the image or the application inside it.
Docker has to be installed and its daemon running before any of it works. The guide on how to install Docker covers that part.
- Pull the image from a registry with docker pull, or let docker run fetch it automatically on first use
- Start the container with docker run, mapping any ports and volumes the application needs
- Confirm it is running with docker ps, and read its output with docker logs
- Stop the container with docker stop when it is no longer needed
- Remove it with docker rm to free the writable layer, or docker rmi to delete the underlying image
The mistake I’d bet on most often is forgetting to publish a port with -p. The application then stays reachable only from inside the container’s own network namespace, and everything looks broken for no obvious reason.
Another one people hit is treating a stopped container as gone. It still exists, exit code and logs intact, until someone explicitly removes it.
Nobody memorizes every flag for these commands. The Docker cheat sheet is easier to keep open in a tab.
When Docker Containers Do Not Work Well

Docker isn’t the right tool everywhere, and pretending otherwise causes more trouble than it saves.
The kernel is the first sticking point. A Linux container can’t run natively on a Windows kernel, and the reverse holds too. Windows-only software on a Linux host still needs a full virtual machine or a Windows container host, and no workaround inside Docker changes that.
Strict multi-tenant isolation is the second. Containers share one kernel, so a kernel vulnerability can, in principle, reach every container on that host. A few examples make the point.
- CVE-2022-0185, a flaw in the kernel’s fs\_context handling
- CVE-2022-0492, a cgroups v1 release\_agent escape
- CVE-2022-0847, the Dirty Pipe vulnerability in the splice syscall
Kernel bugs that weaken container isolation keep surfacing, and each one reminds you that a container is a process boundary, not a hardware one.
Workloads that have to run untrusted, adversarial code on shared infrastructure usually fit better on a hardware-isolated microVM, or on a dedicated virtual machine per tenant.
Legacy applications tied to a specific host setup, like a fixed IP, a licensed hardware dongle or one very particular kernel module, resist containerization just as they resist any standardized packaging.
GUI-heavy desktop software and anything needing direct, low-level hardware access is still easier to run on a full operating system than to force into a container built for headless services.
FAQ on What Is A Docker Container
Is a Docker container the same as a Kubernetes pod?
No. A pod is Kubernetes’s smallest deployable unit and can wrap one or more containers that share a network namespace and storage.
The Docker container is the underlying runtime unit. Kubernetes schedules pods across a cluster, not bare containers.
When should you choose a container over a virtual machine?
Go with a container when workloads are trusted, friendly to being stateless, and need fast scaling on shared infrastructure.
Go with a virtual machine when a workload needs a different kernel, stronger isolation, or compliance requirements a shared host kernel can’t meet.
Can Docker containers run Windows applications?
Only with Windows containers, a separate mode that uses the Windows kernel instead of Linux.
A Linux based Docker Engine can’t run Windows binaries directly. Docker Desktop on Windows works the other way around. It runs Linux containers inside a lightweight virtual machine (WSL 2 or Hyper-V), which is why Linux images work on a Windows laptop.
What common errors show up when running Docker containers?
Port conflicts from an already bound host port come up a lot, along with missing environment variables and permission errors from files owned by a different user inside the container.
A container exiting immediately usually means its main process crashed or finished.
What tools monitor Docker container resource usage?
The built in docker stats command shows live CPU, memory and network use per container.
Production fleets tend to use cAdvisor and Prometheus, which collect the same metrics at scale and feed dashboards that track container density and resource limits over time.
What Should You Fix First Before a Docker Container Reaches Production?
Pin the image tag first. Everything else can wait a step.
Pinning trades automatic updates for reproducibility. A rollback stays predictable only if the exact image you referenced today still exists tomorrow, and skipping the pin risks a silent version drift the next time the base image gets rebuilt upstream.
After that, set CPU and memory limits so one container can’t eat the host, and run the process as a non root user so it drops root privileges.
Once those hold, the natural next stage is wiring the container into a continuous deployment pipeline, where the same image moves from staging to production without manual intervention.
- MySQL Cheat Sheet - September 30, 2026
- How to Remove Duplicate Lines in Notepad++ (Sorted or Unsorted) - September 29, 2026
- Should Your Engineering Team Still Own the Marketing Website? - September 29, 2026



