Containers vs Virtual Machines (VMs): The Basics Before Docker
What You'll Learn
- What containers and virtual machines (VMs) actually virtualize, from first principles
- Why containers are fast and light, and why VMs offer stronger isolation
- How to decide which to use before you ever touch Docker
Quick Summary
- A VM virtualizes hardware, and each VM runs its own guest OS kernel
- A container shares the host kernel and isolates a process with
namespacesandcgroups - Containers win on speed and size; VMs win on isolation. Pick by use case (and they combine well)
Assumptions
- A Linux host (the model is the same on Ubuntu or RHEL-family)
- Containers means Linux containers (Docker / Podman, etc.)
- VMs means hypervisor-based VMs (KVM / VirtualBox / VMware)
What Actually Differs Between Containers and VMs?
Conclusion: A VM virtualizes a whole OS; a container isolates just an app's process. They virtualize different layers.
Both let you run multiple environments on one machine, but they virtualize different layers.
| Aspect | Virtual Machine (VM) | Container |
|---|---|---|
| Virtualizes | Hardware (CPU/memory/NIC) | A process (how it sees the OS) |
| Kernel | Own guest kernel per VM | Shares the host kernel |
| Startup time | Tens of seconds to minutes | Milliseconds to seconds |
| Image size | Several GB | A few MB to a few hundred MB |
| Overhead | Hypervisor layer adds cost | Near-native |
| Isolation | Strong (separate kernels) | Moderate (shared kernel) |
| Different OS | Yes (e.g. Windows on Linux) | No (same kernel as the host) |
A VM reproduces an entire physical machine in software. A container shows each app its own private "world" on top of the same OS. That framing keeps the two straight.
Why Are Containers So Light and Fast?
Conclusion: A container reuses the host kernel instead of booting a new OS, so it starts fast and uses little memory.
The lightness of containers comes down to kernel sharing. Where a VM boots a full guest OS (kernel plus init processes) every time, a container just starts one more process on the already-running host kernel.
The trick that makes that process look like an independent OS is two Linux kernel features.
namespaces (separation)
A namespace partitions what OS resources a process can see. Each type isolates a different view.
- PID: process ID space (inside the container the process sees itself as PID 1)
- mount: filesystem mount points
- network: network interfaces and routing
- UTS: hostname
- IPC: inter-process communication
- user: UID/GID mapping
List the host's current namespaces with lsns.
$ lsns
cgroups (limits)
cgroups (control groups) limit and measure the resources a process may use — CPU, memory, I/O, and more.
$ systemd-cgls
namespaces decide "what you see"; cgroups decide "how much you get" Combine the two to isolate a single process so it behaves like a standalone OS. That is what a container really is.
How Does a Virtual Machine Work?
Conclusion: A hypervisor virtualizes the hardware, and a full guest OS boots on top of it.
A VM relies on a hypervisor that virtualizes hardware — CPU, memory, disk, NIC. The guest OS boots as if that hardware were real.
Hypervisors come in two broad kinds.
- Type 1 (bare-metal): runs directly on hardware. KVM / Xen / VMware ESXi. The basis of servers and cloud.
- Type 2 (hosted): runs on top of a host OS. VirtualBox / VMware Workstation. Good for local testing.
Because each guest runs its own kernel, you can run Windows on a Linux host, alongside a different Linux version. A container, sharing the host kernel, cannot do that.
Which Has Stronger Isolation (Security)?
Conclusion: VMs isolate more strongly. Containers share a kernel, so a kernel vulnerability can affect every container.
A VM gives each guest its own kernel, so compromising one VM does not directly spill into others or the host. The boundary sits at the hardware-virtualization level.
A container shares the host kernel. The flip side of being light is that a kernel vulnerability leaves the theoretical risk of a "container breakout" from the container to the host.
A container is not a "lightweight VM." The isolation level differs, so when strong separation is a requirement, use a VM — or combine VMs and containers.
In practice the common cloud pattern is to run containers inside a VM: the VM provides a strong boundary, while containers inside it keep their lightness and portability.
Which Should You Use?
Conclusion: Containers for packaging, distribution, and density; VMs for a different OS, strong isolation, or kernel-level testing.
A rough guide by goal:
| What you want to do | Better fit |
|---|---|
| Package and ship an app with its environment | Container |
| Microservices / CI/CD | Container |
| Pack many environments densely on one host | Container |
| Run a different OS (e.g. Windows on Linux) | VM |
| Strong isolation / multi-tenant boundary | VM |
| Test kernel modules or the OS itself | VM |
When unsure, ask:
- Is the host kernel enough? If yes, a container is the first candidate.
- Do you need a different OS or custom kernel? If yes, use a VM.
- How strict is the isolation requirement? The stricter it is, the more a VM (or containers inside a VM) fits.
What to Know Before Learning Docker
Conclusion: Docker wraps namespaces and cgroups in a friendly tool. Knowing the mechanics, its commands read as logic, not magic.
Once you start with Docker you meet two words: image and container. Mapping them to the mechanics above prevents confusion.
- Image: the "blueprint" for a container — a read-only template bundling the app and its dependencies
- Container: a "running process" started from an image — really a Linux process isolated by namespaces and cgroups
So Docker is just a tool that wraps the kernel features you saw here into a human-friendly form. Drop the "container = ultra-light VM" misconception and the Docker commands start to read naturally.
This much understanding is enough "Shares the kernel, separated by namespaces, limited by cgroups" — keep that one line in mind and Docker's introduction goes smoothly.