Chapter 1: Foundations
Topic 02

Containers vs Virtual Machines

ConceptIsolation

A virtual machine virtualizes hardware. A hypervisor carves a physical host into VMs, each with its own emulated CPU, memory, and devices, and each boots a full guest operating system with its own kernel. A container virtualizes the operating system instead: it is a process running on the host's kernel, handed an isolated view of the system, with no guest OS to boot at all.

That single architectural difference — own kernel versus shared kernel — explains almost everything that follows. It is why a VM takes tens of seconds to start and a container takes milliseconds, why a VM image is gigabytes and a container image is megabytes, and why a VM's isolation is stronger than a container's. The two are not rivals so much as different points on the weight-versus-isolation curve.

The Stack, Side by Side

Stack a VM from the bottom: physical hardware, then a hypervisor, then for each VM a full guest kernel, its userland of libraries and binaries, and finally the application. Stack a container: physical hardware, the host's single kernel, then for each container just its userland and the application. The container stack is missing two whole layers — the hypervisor and the per-instance guest kernel — and those two missing layers are the entire story of why containers are light.

Two ways to isolate an application
Virtual machine
Hardware → hypervisor → guest kernel → guest userland → app. Each VM boots its own OS. Gigabytes, seconds to start.
Container
Hardware → shared host kernel → container userland → app. No guest OS. Megabytes, milliseconds to start.

Shared Kernel, Separate Userland

Every container on a host shares that host's one kernel, but each carries its own userland — its own libraries, its own coreutils, its own view of the filesystem. This is why a container built on Ubuntu userland runs fine on a host running a different distribution: the kernel is shared and compatible, while the userland that differs travels inside the image. What a container cannot do is run a userland that needs a different kernel — the kernel is the host's, and there is exactly one.

Weight and Startup

A VM image carries a whole operating system, so it is measured in gigabytes and "starting" it means booting that OS — initializing devices, starting init, bringing up services — which takes tens of seconds. A container image carries only the app and its userland, so it is measured in tens to hundreds of megabytes, and "starting" it means forking a process the kernel fences off, which takes milliseconds. That ratio is why you run dozens of containers on a host that would hold a handful of VMs, and why autoscaling containers feels instant where autoscaling VMs feels slow.

The Isolation Trade-off

The VM's boundary is enforced in hardware by the hypervisor; the container's boundary is enforced in software by the host kernel. The hardware boundary is stronger. A kernel exploit inside a container can, in principle, reach the host and every other container sharing that kernel, in a way a guest-kernel exploit cannot cross a hypervisor. This is why genuinely untrusted or hard multi-tenant workloads sometimes still run in VMs, or in VM-backed container runtimes that deliberately put a hypervisor back under the container interface — you trade some startup speed for a harder wall.

Why Docker Desktop Runs a VM

Linux containers need a Linux kernel to share, and macOS and Windows do not have one. So Docker Desktop quietly runs a lightweight Linux virtual machine, and your containers live inside it — the "host kernel" they share is the VM's kernel, not your laptop's. On a Linux machine there is no such layer; containers run directly on the machine's own kernel.

This hidden VM is invisible most of the time and then suddenly relevant. It is why a container cannot see your Mac's processes, why bind-mount file I/O is slower on Docker Desktop than on native Linux (it crosses the VM boundary), and why "it's fast on the server but sluggish on my laptop" is a common and expected gap. Knowing the VM is there turns those surprises into predictable consequences.

Container vs Virtual Machine

Virtual machine — boots its own guest kernel under a hypervisor: strong hardware-enforced isolation, gigabytes, seconds to start. Reach for it when you need a hard multi-tenant boundary, an untrusted workload contained, or a different kernel than the host.

Container — an isolated process on the shared host kernel: lighter, megabytes, milliseconds to start, with a software-enforced boundary that is weaker than a hypervisor's. Reach for it for packaging and density on trusted workloads. The two compose — containers frequently run inside VMs.

Common Mistakes
  • Expecting container isolation to be as strong as a VM's and running untrusted code beside sensitive workloads on a shared kernel — a single kernel vulnerability is a shared blast radius across every container on the host.
  • Trying to run a Windows container image on a Linux host or the reverse — there is no shared kernel to make that work; the container's OS family must match the host kernel.
  • Sizing a host as if containers were VMs and under-packing it by an order of magnitude — containers are far lighter, and provisioning one heavyweight machine per container wastes most of the hardware.
  • Assuming millisecond startup means there is no operating system underneath — the host kernel still does all the real work, so a bad kernel module or driver degrades every container at once.
Best Practices
  • Reach for containers for packaging and density on trusted workloads, and reserve VM-strength isolation for genuinely untrusted code or hard multi-tenant boundaries.
  • Match the container's OS family to the host kernel — Linux containers on a Linux kernel — and let Docker Desktop's hidden VM handle that boundary for you on macOS and Windows.
  • Right-size hosts for container density rather than VM weight, so a single machine carries many containers instead of a few oversized ones.
  • Combine the two deliberately when you want both properties — run containers inside VMs to get the packaging model and the stronger boundary together, rather than treating it as an either/or choice.
Comparable tools VMware · KVM · Hyper-V the hypervisors that provide the VM model Kata · Firecracker · gVisor VM-strength boundaries under a container interface LXC · LXD system containers, closer to lightweight VMs

Knowledge Check

What is the one architectural difference that distinguishes a container from a virtual machine?

  • A VM boots its own guest kernel, while a container shares the host's kernel
  • A VM can run whole classes of applications that a container fundamentally cannot
  • A container encrypts its filesystem at rest while a VM leaves its disk in the clear
  • A container runs directly on physical hardware while a VM runs only in a cloud

Why does a container start in milliseconds while a VM takes tens of seconds?

  • Starting a container forks a process, while starting a VM boots an entire guest operating system
  • Container images are pre-compiled to native machine code while VM images are interpreted at boot
  • Containers start faster because they skip the network initialization step that every VM requires at boot
  • Containers run entirely in memory and never touch disk, while a VM must read its image off the disk

When is a virtual machine still the better choice over a container?

  • When you need a hard isolation boundary for untrusted workloads, or a different kernel than the host
  • When you want to pack the maximum possible number of independent workloads onto a single physical host
  • When you need the fastest possible cold-start time to scale instances up and down for autoscaling
  • When you want to ship the application and all of its dependencies together as one small portable artifact

Why does Docker Desktop run a Linux VM on macOS and Windows?

  • Linux containers need a Linux kernel to share, which those operating systems do not provide
  • The VM is required to sandbox containers for security on desktop machines, which are more exposed
  • The VM accelerates container workloads so they run faster than they would directly on the host
  • Docker's license requires a VM layer on every operating system it supports, including Linux

You got correct