fivenines
2/40
Lesson 2 · Foundations

Containers vs. Virtual Machines

In one sentence: A VM virtualizes hardware to boot a whole guest operating system; a container virtualizes the operating system to isolate just a process tree — which is why containers start in milliseconds, not minutes.

You already know

  • From Lesson 1: a container is a running instance of an image, managed by a daemon.
  • VMs from everyday use: they're heavy, boot slowly, and each carries a full OS.

Two places to draw the line

Isolation always means drawing a line and lying to whatever is above it. A hypervisor draws the line at the hardware: each guest gets fake CPUs, fake disks, fake network cards, and must boot its own kernel to drive them. A container engine draws the line at the kernel's system-call interface: every container shares the one real host kernel, but the kernel lies to each process tree about what it can see — its own process list, its own filesystem root, its own hostname. Nothing boots; a container "starting" is just a normal process starting inside a set of kernel-enforced lies.

Architecture — where the isolation line sits
flowchart TB
  subgraph VM["Virtual machines"]
    direction TB
    A1["App A"] --> G1["Guest OS + kernel A"]
    A2["App B"] --> G2["Guest OS + kernel B"]
    G1 --> HV["Hypervisor  ⟵ isolation line"]
    G2 --> HV
    HV --> HW1["Hardware"]
  end
  subgraph CT["Containers"]
    direction TB
    B1["App A + libs"] --> K["Shared host kernel  ⟵ isolation line"]
    B2["App B + libs"] --> K
    ENG["Container engine"] -. configures .-> K
    K --> HW2["Hardware"]
  end
    

The cost of the difference

Because a VM must initialize virtual hardware and boot a kernel, startup is measured in seconds to minutes and each guest costs gigabytes of memory before the app runs. A container skips all of it — the kernel is already running. The trade: containers offer a weaker boundary (one shared kernel means one kernel bug can cross the line), which is why Part 1 ends with a security lesson and Lesson 39 hardens it further.

Sequence — starting an app both ways
sequenceDiagram
  participant HV as Hypervisor
  participant G as Guest OS
  participant E as Container engine
  participant K as Host kernel
  rect rgb(253, 244, 235)
  note over HV,G: VM path — seconds to minutes
  HV->>G: allocate vCPU, vRAM, vDisk
  G->>G: boot kernel, mount fs, run init
  G->>G: finally, start the app
  end
  rect rgb(235, 245, 253)
  note over E,K: Container path — milliseconds
  E->>K: create isolated view (namespaces)
  E->>K: apply resource limits (cgroups)
  E->>K: exec the app process
  end
    

Anchor these

  • VM = fake hardware + real guest kernel. Container = real shared kernel + fake view.
  • Nothing "boots" in a container — it's a process with a restricted worldview.
  • Speed comes from sharing the kernel; the security trade-off comes from the same place.
Next step

See what actually stuck.

Take the practice scenarios now.