20.1.1.1 VM Contrast Lesson
A focused guide to VM Contrast Lesson, connecting core concepts with practical Docker and container operations.
Containers and virtual machines (VMs) both solve the problem of isolating applications from each other and from the underlying host, but they do so at fundamentally different layers of the technology stack. Understanding how they differ explains when to use each and why containers have become the preferred deployment unit for most modern application workloads.
The Fundamental Architectural Difference
A virtual machine virtualizes hardware. It runs a complete, separate operating system — including its own kernel — on top of a hypervisor that allocates physical hardware resources (CPU, memory, disk, network) to it. Each VM believes it has its own dedicated machine, because from its kernel's perspective it does.
A container virtualizes the operating system user space. It shares the host kernel and hardware directly but is isolated from other containers using Linux kernel features: namespaces (which give each container its own view of the process list, network, and filesystem) and cgroups (which enforce resource limits). There is no separate kernel inside the container, no hypervisor, and no hardware virtualization.
Isolation Mechanism
Virtual Machine isolation is provided by the hypervisor, which sits between the guest OS and the hardware. The guest OS kernel has no direct access to the physical hardware and cannot see or affect other VMs. A compromise of one VM's guest kernel does not inherently compromise the host or other VMs, because the hypervisor enforces the boundary.
Container isolation is provided by the Linux kernel's namespaces and cgroups. Containers share the host kernel, which means:
- A vulnerability in the shared kernel can affect all containers simultaneously.
- A container with sufficient privileges can potentially escape its namespace and access the host.
- Containers are isolated at the OS level, not the hardware level.
For workloads requiring strong tenant isolation (untrusted code, multi-tenant SaaS), VMs or hardware-isolated container runtimes (Kata Containers) provide stronger guarantees than standard containers.
Resource Overhead
A VM must allocate and boot a full OS for every workload. A minimal Linux VM image is typically 500MB to several GBs. The VM kernel runs continuously, consuming memory (typically 256MB to 1GB or more just for the guest OS processes) even when the application is idle.
A container image contains only the application and its user-space dependencies. A minimal Alpine Linux container image is 7MB. The container has no separate kernel process — it uses the host kernel. Hundreds of containers can run on a host where only tens of VMs could fit.
Startup Time
VMs take seconds to minutes to boot because the hypervisor must allocate hardware resources, load the bootloader, start the kernel, initialize the OS, and start system services before the application can run.
Containers start in milliseconds to seconds because the kernel is already running on the host. Starting a container is comparable to starting a process, not booting a machine.
Portability
Both containers and VMs are more portable than bare-metal applications. However, container images are smaller, registry-distributable, and architecture-agnostic in their definition (a Dockerfile produces different image variants per architecture from the same source). VM images (VMDK, OVA, AMI) are typically larger and more tied to the hypervisor or cloud platform format.
When to Use Each
Containers are preferred for:
- Microservices and application workloads.
- CI/CD build and test pipelines.
- Stateless application replicas.
- Fast autoscaling deployments.
- Developer environments that need consistency across machines.
Virtual Machines are preferred for:
- Full OS-level isolation (security compliance, multi-tenant workloads).
- Running a different operating system (Windows applications on a Linux host, or vice versa).
- Workloads that require dedicated kernel configuration.
- Environments where containers are not supported at the infrastructure level.
In modern infrastructure, containers and VMs coexist: VMs provide the isolated compute nodes on which Docker runs, and containers provide the application isolation within those nodes. Cloud providers run Docker containers inside VMs (EC2 instances, GCE VMs, Azure VMs) as the standard deployment model.
Verifying Container Isolation in Practice
To confirm that a container shares the host kernel but has its own process namespace:
docker run --rm alpine uname -r
The output shows the host kernel version — the same kernel the host is running — because the container uses the host kernel directly.
docker run --rm alpine ps aux
The output shows only the ps process itself — no host processes are visible inside the container because the PID namespace is isolated.