Docker vs VM

Containers and VMs both isolate apps on one server, but at different layers. Containers share the host kernel (fast, dense, thinner boundary); VMs virtualize hardware (slower, isolated, any OS). In the cloud, you run containers inside VMs.

Banner

Prefer to watch? ▶ Docker vs VM in 90 seconds ✈ Telegram

A container and a virtual machine both run your app in its own isolated box on the same server. But they isolate at completely different layers — and that difference cascades into resource use, speed, security, and how you actually deploy them.

Mental model: A container is a process with a borrowed kernel; a VM is a whole computer in software.


What is a container, really?

A Docker container isn't a tiny computer. It's your application and its libraries running as isolated processes on the host machine — they share the host's kernel with everything else on that machine.

Linux namespaces create the illusion of isolation: each container sees its own filesystem, network stack, process table, and hostname. cgroups enforce resource limits: this container gets at most 512 MB of RAM, this one gets 2 CPUs. The kernel enforces both. The host OS kernel is still one, still shared.

The upshot:

  • Image size: ~50 MB (just your app + libraries; no OS)
  • Boot time: under one second (start a process, apply namespace/cgroup rules)
  • Density: hundreds of containers on a single host
  • Overhead: minimal (a few MB of RAM per container; microseconds of syscall overhead)

The cost:

  • Thinner boundary: namespaces and cgroups are kernel-enforced, but a kernel exploit or a well-crafted container escape can potentially breach into the host or sibling containers
  • Kernel lock-in: you cannot run a Windows kernel on a Linux host. On Mac or Windows laptops, Docker runs a hidden Linux VM behind the scenes so containers have a Linux kernel to share — you pay the VM tax invisibly

What is a virtual machine?

A virtual machine uses a hypervisor — software like KVM, ESXi, or Hyper-V — to simulate hardware. Each VM boots a complete guest operating system with its own kernel. From the guest OS's perspective, it owns the machine. The hypervisor intercepts hardware requests and routes them to real hardware or other VMs.

The upshot:

  • Image size: gigabytes (a full OS + your app)
  • Boot time: tens of seconds (the guest OS must initialize, load drivers, run services)
  • Density: far fewer per host (a single high-end server might run 10–20 VMs comfortably)
  • Isolation: a bug, exploit, or malicious code in one VM cannot access the hypervisor, host, or other VMs. The boundary is enforced in hardware and firmware
  • OS flexibility: run Windows on a Linux hypervisor, or vice versa

Head-to-head comparison

AspectContainer (Docker)Virtual Machine
Image size~50 MBGigabytes
Boot time<1 secondTens of seconds
Density (per host)HundredsTens
KernelShared (host kernel)Own kernel per VM
Isolation boundaryNamespaces + cgroups (kernel-enforced, thinner)Hypervisor + hardware (stronger)
OS flexibilityLocked to host kernelAny guest OS
Security modelSuitable for trusted multi-tenancySuitable for untrusted multi-tenancy

The real-world answer: both, layered

You will hear engineers debate: "Should we use containers or VMs?" The honest answer is: you use both.

In every major cloud platform — AWS ECS, Google Kubernetes Engine (GKE), AWS Fargate — containers run inside VMs:

  1. The VM is the trust boundary. Each customer or tenant gets their own VM (or a VM shared only with other instances from the same account). This is the hard isolation that prevents one customer's code from crashing another customer's workload.

  2. Containers are the app boundary. Inside a VM, you run dozens or hundreds of containerized microservices. Containers give you fast startup, small images, and easy portability. If one container crashes, it doesn't bring down the whole VM — you just restart that container.

  3. The payoff: You get the density and speed of containers, wrapped in the isolation and control of VMs.

When cloud providers say "serverless" (Fargate, Cloud Run), they're abstracting away the VM layer entirely, but it's still there — you've just delegated management to the cloud. The container still runs inside a VM; you just don't see it.


When to reach for each

Containers (Docker):

  • Your app is portable, your environment is trusted, and you want fast iteration
  • You're deploying on a fleet you control (your own Kubernetes cluster, or a managed service like EKS)
  • You want to pack maximum density onto hardware you own or pay for by the hour

Virtual machines:

  • You need strong isolation between untrusted workloads (multi-tenant SaaS, regulated compliance)
  • You need to run a guest OS that differs from the host (Windows apps on a Linux datacenter)
  • You're renting infrastructure where hypervisor isolation is the contract with your cloud provider

Both (containers inside VMs):

  • You're building a production cloud system — this is the default in AWS, Google Cloud, and Azure

Why containers can't replace VMs

Containers are faster and denser, but they inherit the host kernel's behavior and bugs. If a kernel vulnerability exists, all containers on that host are exposed. VMs add a second layer: even if a guest OS is compromised, the hypervisor and other VMs are protected.

For public clouds serving multiple customers, this is non-negotiable. For internal infrastructure where you trust your developers and ops team, containers alone are often enough.


Verdict

Reach for containers when speed, density, and portability matter more than hard isolation. Reach for VMs when isolation is the primary requirement. In production, you'll almost certainly reach for both — containers running inside VMs — because they solve different problems at different scales.

Watch the 90-second reel to see this concept illustrated step by step.

Docker vs VM | Vahid Aghajani