Containers vs Virtual Machines (VMs): The Basics Before Docker

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 namespaces and cgroups
  • 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:

  1. Is the host kernel enough? If yes, a container is the first candidate.
  2. Do you need a different OS or custom kernel? If yes, use a VM.
  3. 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.

Next Reading