Search

How Docker Containers Work (and How They Differ From VMs)

The short answer

Quick answer: A container is an ordinary process running on the host's operating system kernel, with restrictions that make it believe it has a machine to itself. Linux namespaces limit what the process can see: its own process list, network interfaces and file system. Control groups (cgroups) limit what it can use: CPU, memory and disk I/O. A container image packages the application with all of its libraries and files, so it runs the same way everywhere. A virtual machine, by contrast, emulates a whole computer and runs a complete guest operating system. Containers share the host kernel, which makes them start in milliseconds and use far less memory, at the cost of weaker isolation.

The problem containers solve

"It works on my machine" is one of the oldest complaints in software. An application depends on a particular language version, system libraries, configuration files and environment variables. A slight difference between a developer's laptop and the production server causes failures that are painful to diagnose.

Containers fix this by shipping the application together with its entire environment. If it runs in the container on your laptop, the same container runs on the server.

A container is a process

There is no "container" object in the Linux kernel. A container is a normal process (see what happens when you run a program) started with three kernel features applied to it. The Docker overview describes the same building blocks.

Namespaces: what the process can see

A namespace gives a process its own private view of one part of the system.

NamespaceIsolatesEffect inside the container
PIDProcess IDsIts main process is PID 1 and it cannot see the host's processes
NetworkInterfaces, IP addresses, ports, routesIt has its own network stack and can listen on port 80 without conflict
MountThe file system treeIt sees only its own files
UTSHostnameIt has its own hostname
IPCShared memory and message queuesIt cannot interfere with other processes' IPC
UserUser and group IDsRoot inside can be an unprivileged user outside

Control groups: what the process can use

Cgroups set limits and track usage:

  • A maximum amount of memory. Exceed it and the process is killed.
  • A share of CPU time.
  • Limits on disk and network I/O and on the number of processes.

Without them, one misbehaving container could starve every other one on the host.

A private root file system

The container's root directory is switched to the image's file system. The process sees a complete Linux directory tree, with /bin, /lib and /etc, that belongs to the image, not to the host.

Additional restrictions tighten security: dropped capabilities, seccomp filters that block risky system calls, and mandatory access control profiles.

Images and layers

A container image is a read-only template: a file system snapshot plus metadata such as which command to run.

Images are built from a Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Each instruction creates a layer: a set of file changes on top of the previous one. Layers are identified by a hash of their content. This design pays off in several ways:

  • Sharing. Ten images built on the same base store that base once.
  • Caching. If a layer and everything before it are unchanged, the build reuses it. That is why dependencies are copied and installed before the application code: code changes often, dependencies rarely.
  • Fast distribution. Pushing or pulling an image transfers only the layers the other side lacks.

When a container starts, a union file system stacks the read-only layers and adds a thin writable layer on top. Changes made inside the container go there, using copy-on-write. Delete the container and that layer is gone.

Layers never shrink an image retroactively: a file added in one layer and deleted in the next still exists in the first. Secrets copied into an image stay recoverable for the same reason.

Containers vs virtual machines

Virtual machineContainer
What is virtualisedHardwareThe operating system
KernelEach VM runs its ownShared with the host
IncludesA full guest OSOnly the app and its libraries
Start timeSeconds to minutesMilliseconds to seconds
SizeGigabytesMegabytes
Memory overheadA whole OS per VMLittle beyond the app itself
IsolationStrong: a hardware boundary enforced by the hypervisorWeaker: a shared kernel
Density per hostTensHundreds or thousands
Can run a different OSYesNo: Linux containers need a Linux kernel

A hypervisor runs virtual machines, each with a full operating system that believes it is on real hardware. A container runtime asks the one host kernel to start isolated processes.

They are complementary. In the cloud, containers almost always run inside virtual machines: VMs separate customers, and containers pack applications efficiently within them.

When Docker runs on macOS or Windows, it quietly runs a small Linux virtual machine, because Linux containers need a Linux kernel.

Security: the shared kernel

Because all containers on a host use the same kernel, a kernel vulnerability, or a container given too many privileges, can allow an escape to the host. Sensible practice:

  • Do not run as root inside the container.
  • Never use privileged mode unless you fully understand why.
  • Use minimal base images and scan them for known vulnerabilities.
  • Keep the host kernel patched.
  • Do not put secrets in images.

For workloads that need stronger separation, sandboxed runtimes add a layer: gVisor intercepts system calls in user space, and Kata Containers and Firecracker wrap each container in a lightweight virtual machine.

Data and networking

  • Storage. The container's writable layer is temporary. Data that must survive goes in a volume, storage managed outside the container's lifecycle, or a bind-mounted host directory.
  • Networking. By default containers join a private virtual network on the host. To make a service reachable from outside, a host port is mapped to a container port, using the same address translation idea described in how NAT works.

Docker and the wider ecosystem

Docker made containers popular in 2013 by giving them a simple tool and image format. The underlying kernel features already existed.

Today the formats are open standards under the Open Container Initiative (OCI): an image built with one tool runs under any compliant runtime. The pieces:

ComponentRole
Docker CLI and daemonBuild, run and manage containers on one machine
containerdThe runtime that manages container lifecycles
runcThe low-level tool that sets up namespaces and cgroups and starts the process
Registry (Docker Hub and others)Stores and distributes images
Podman, BuildahAlternative tools without a central daemon

Running containers across many machines needs an orchestrator; see what Kubernetes does. Building images automatically is usually part of a CI/CD pipeline.

Good habits

  1. Use small, specific base images, and pin versions.
  2. Order Dockerfile steps from least to most frequently changing.
  3. Use multi-stage builds so compilers and build tools stay out of the final image.
  4. One main process per container.
  5. Treat containers as disposable: no important state inside.
  6. Set memory and CPU limits.

Frequently asked questions

What is the difference between a container and a virtual machine?

A virtual machine emulates hardware and runs a complete operating system. A container is an isolated process sharing the host's kernel, which makes it far lighter and faster to start.

What is the difference between an image and a container?

An image is a read-only template. A container is a running instance of an image, with a writable layer on top.

Are containers secure?

They provide useful isolation, but weaker than virtual machines, because the kernel is shared. Run them with minimal privileges and keep hosts patched.

Is Docker the same as a container?

No. Docker is one set of tools for building and running containers. The technology underneath is part of the Linux kernel, and other tools use it too.

Conclusion

A container is not a small virtual machine. It is an ordinary process that has been given a restricted view of the system and a budget of resources, started from an image that carries everything it needs. That simplicity is why containers start instantly and pack densely, and the shared kernel is why they need care when isolation really matters.

Related articles

Sources and further reading

Usama Muneer

Usama Muneer

Coder, Blogger, Tech Speaker & Web Technologies Enthusiast. Passionate about working on open-source Programming languages & Tools while utilizing my Product Development skills.

Your experience on this site will be improved by allowing cookies Cookie Policy