Is Docker Just a VM? A Practitioner’s Guide to What Actually Works
Look, I get it. You've heard the hype. Docker this, containers that. Someone on your team says "just throw it in a Docker container" and you think — isn't that basically a VM but smaller?
I asked myself the same question in 2018 when I started SIVARO. Two years earlier, I'd spent 16 hours debugging a VM image deployment that worked on my machine but exploded on staging. The image was 4GB. Boot time was 3 minutes. And someone had accidentally left a MySQL instance running in the base image.
Docker isn't a VM. Not even close. But the confusion isn't stupid — it's understandable. Both solve the same problem: "it works on my machine." But they solve it so differently that picking the wrong one costs you real money.
This guide isn't a Wikipedia article. It's what I've learned building production AI systems and data infrastructure that process 200K events per second. I'll show you the architecture, the trade-offs, and the one question you should ask before choosing.
What Is a Docker and Why Is It Used? (The 30-Second Honest Answer)
A Docker container is a running process that thinks it has its own operating system. It doesn't. It shares the host's kernel, but uses Linux namespaces and cgroups to pretend it owns the filesystem, network, and process tree.
Docker's official docs put it cleanly: "A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another."
Why use it? Three reasons:
- Reproducibility — Your dev environment matches production. I can't tell you how many times I've seen "works on Joe's laptop" break because Joe had Python 3.9 and prod had 3.7. Docker kills that.
- Density — A single server runs 10x more containers than VMs. That's not marketing. We tested it at SIVARO: a 16-core machine ran 40 containers for a microservice architecture. Same machine ran 4 VMs before crashing.
- Speed — Containers start in milliseconds, not minutes.
But don't confuse density with security. Containers share the kernel. Break the namespace isolation and you're inside the host. This Reddit thread nails the ELI5: "A VM is a whole house with its own foundation. A container is an apartment in a building — you share the plumbing and electrical."
The Architecture: Where "Is Docker Just a VM?" Falls Apart
Let's draw the line. This matters because your infrastructure costs, security posture, and debugging strategy all flow from this distinction.
VMs: The Honest Lie
A VM runs a full operating system — kernel, drivers, init system, everything — on top of a hypervisor. The hypervisor translates hardware calls. Each VM is a self-contained machine.
[Hardware]
[Hypervisor (VMware, KVM, Hyper-V)]
[VM1: Kernel + OS + App]
[VM2: Kernel + OS + App]
Each VM ships its own kernel. That's 100-500MB just for the kernel. Plus init system. Plus system libraries. A minimal Linux VM is often 2GB. A Windows VM? 8-15GB.
Docker Containers: The Lean Imposter
A container runs as a process on the host kernel. It uses namespaces to isolate what the process sees — its own filesystem tree, process IDs, network stack. Cgroups limit what it uses — CPU, memory, disk I/O.
[Hardware]
[Host OS with Linux Kernel]
[Docker Engine]
[Container 1: App (shares host kernel)]
[Container 2: App (shares host kernel)]
Amazon's comparison puts numbers on this: "A Docker container image is typically in the tens of megabytes, while a VM image can be in the gigabytes."
The practical difference? I can pull a new container image in 2 seconds on a good connection. A full VM image? Leave it running overnight.
Why Smart People Confuse Them (And Why It's Dangerous)
Here's the trap: Docker looks like a VM because you docker run ubuntu and get a shell. It feels like SSHing into a server.
But docker run ubuntu doesn't boot a kernel. It starts a process that mounts an Ubuntu filesystem. The kernel underneath is whatever your host runs. Try uname -r inside a Docker container on your Mac — it'll show the Linux kernel version from the VM Docker Desktop runs. Your container isn't running Ubuntu's kernel. It's faking it.
Why this matters for security: If a container escapes, it has direct access to the host kernel. With a VM, a hypervisor break is orders of magnitude harder. Docker's own documentation warns: "Containers run on the same kernel as the host. If the kernel has a vulnerability, containers can be exploited."
At SIVARO, we run containers for stateless microservices. We run VMs for anything that touches customer PII. The added isolation cost is worth it.
Real Numbers: Docker vs VM in Production
Let me give you actual data from our infrastructure.
Boot time (cold start):
- VM (Ubuntu 22.04, KVM): 45 seconds to SSH-ready
- Docker container (Ubuntu 22.04 base): 0.3 seconds to process start
Memory overhead per instance:
- VM: ~500MB (kernel + system services)
- Container: ~10MB (just the process)
Maximum instances on a 32GB machine with 8 cores:
- VMs: 15 (conservative, with 2GB each for app)
- Containers: 120+ (100MB each for app)
I'm not cherry-picking. These are production numbers from our event processing pipeline. This YouTube breakdown by a systems engineer shows similar ratios.
But — and this is the part people skip — containers don't win everything. Disk I/O is worse in containers because of the layered filesystem. Network throughput requires tuning (CNI plugins, eBPF). Monitoring is harder because processes are ephemeral.
Can I Learn Docker in 2 Days?
Yes. But you'll learn the wrong way.
The question "can I learn Docker in 2 days?" is like asking "can I learn driving in 2 days?" You can move the car. You can't handle a highway merge or parallel park.
Here's what you can learn in 2 days:
docker run,docker build,docker compose- Writing a basic Dockerfile
- Running a web server in a container
Here's what takes months:
- Container networking (bridge, host, overlay modes)
- Multi-stage builds for minimizing image size
- Persistent storage (volumes vs bind mounts)
- Security contexts and seccomp profiles
I've seen teams "learn Docker in 2 days" then deploy containers with --privileged flags because they couldn't figure out volume permissions. Don't be that team.
FPT AI's guide recommends starting with a single service, not a microservice architecture. Good advice. Start small, break things, learn.
When Docker Isn't the Answer (Hard Truths)
Most articles tell you Docker solves everything. They're wrong. Here's when you should use VMs instead:
1. You need a different kernel
Can't run Windows containers on a Linux host natively. Need to test kernel modules? Need specific kernel configs? Use a VM.
2. Security isolation matters
Multi-tenant environments where tenants don't trust each other. VMs provide hardware-level isolation. Containers share a kernel — one bad CVE and everyone's compromised.
3. You're running legacy OSs
A container can't run a different kernel. Need Ubuntu 18.04? Fine — same kernel family. Need FreeBSD or Solaris? You need a VM.
4. Performance for certain workloads
Database workloads with heavy I/O. Containers add a filesystem layer that hurts random writes. We tested PostgreSQL in a container vs VM — the VM was 15% faster on write-heavy workloads. AWS's comparison notes: "VMs offer more consistent performance guarantees."
The Hybrid Approach (What We Actually Run)
Here's what I tell clients at SIVARO: run both. Containers for the stateless stuff, VMs for the stateful stuff.
Our production stack:
- Kubernetes (containers) for: API servers, event processors, ML inference endpoints
- VMs for: Databases (PostgreSQL, Redis), message queues (Kafka), anything with persistent state
Why? Containers make scaling stateless services trivial. But stateful services need stable storage, predictable networking, and hard security boundaries — VMs deliver that.
endjin's introduction makes a similar argument: "Containers excel at microservices and CI/CD pipelines, while VMs are [better suited for applications with complex system dependencies or specific kernel requirements."
Writing a Dockerfile That Actually Works (Lessons from Breaking Things)
Let me save you the pain I went through.
The Wrong Way
dockerfile
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
This image is 1.2GB. It includes build tools, development dependencies, and your entire source history. Layers are bloated. Every rebuild takes 5 minutes.
The Right Way
dockerfile
FROM node:18-alpine AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production
COPY src/ ./src/
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /build/node_modules ./node_modules
COPY --from=builder /build/dist ./dist
EXPOSE 3000
USER node
CMD ["node", "dist/server.js"]
Size: 180MB. Rebuild time: 20 seconds. No root user inside the container. Production-ready.
But here's what no one warns you about: npm ci can break if your package-lock.json doesn't match package.json. That's a lesson I learned at 2 AM debugging a broken deployment. The lockfile is your friend — commit it.
Debugging Containers: The Missing Manual
When something breaks inside a container, you can't SSH in. There's no SSH server. There might not be a shell.
Here's how I debug:
bash
# Get a shell inside a running container
docker exec -it container_name sh
# Run the same image but override the command
docker run --rm -it myimage /bin/sh
# Copy files out for inspection
docker cp container_name:/app/logs/error.log ./error.log
# Check what's happening in the container
docker inspect container_name
docker logs container_name --tail 100 --follow
Pro tip: Build a debug image with tools you need (curl, vim, strace) but never deploy it to production. Use a separate tag:
dockerfile
FROM myapp:latest AS debug
RUN apk add --no-cache curl vim strace
Debugging containers is harder than debugging VMs. The payoff is worth it, but don't pretend it's easier. This Docker overview has a section on debugging that I've bookmarked. Use it.
The "Is Docker Just a VM?" FAQ Section
Q: Is Docker just a VM?
No. Docker shares the host kernel. VMs run their own kernel. Docker starts containers in milliseconds. VMs boot in 30-90 seconds. Docker containers are processes. VMs are complete operating systems.
Q: Can I run Windows containers on Linux?
Only with a VM underneath. Docker Desktop on Mac runs a Linux VM to host containers. Windows containers require a Windows host or VM.
Q: What is a Docker and why is it used?
Docker packages an application with its dependencies into a container. It's used to make deployments reproducible, reduce infrastructure costs through higher density, and speed up development workflows.
Q: Can I learn Docker in 2 days?
You can learn the basics in 2 days: docker run, docker build, basic Dockerfiles. You'll need weeks to understand networking, security, volume management, and production deployment patterns.
Q: Is Docker safer than VMs?
No. VMs provide stronger security isolation because they don't share the kernel. Containers are safer than running processes directly on the host (due to namespaces and cgroups), but they're not as isolated as VMs.
Q: Can I run Docker inside a VM?
Yes. This is common for CI/CD pipelines and testing. It adds overhead but provides flexibility. We do this for security testing at SIVARO.
Q: Does Docker replace Kubernetes?
No. Docker is a container runtime. Kubernetes is an orchestrator that manages containers across multiple machines. They complement each other — Kubernetes typically uses Docker (or containerd) to run containers.
Q: What happens to containers when the host restarts?
By default, containers stop and don't restart. Use --restart always or --restart unless-stopped for production. Or use Docker Compose / Kubernetes to manage restarts.
The Simple Decision Framework
Still confused? Ask yourself one question:
Do I need to control the kernel?
- Yes → Use a VM
- No → Use Docker
That's it. Everything else — portability, speed, density — follows from that core distinction.
If you're running microservices on Linux, use containers. If you're running a legacy app that needs a specific kernel module, use a VM. If you need both, use both — just know why.
I've built infrastructure that scaled from 0 to 200K events/sec. The stack was containers on VMs. Not one or the other. Both, with clear boundaries.
Final Thought (No Conclusion, Just a Prediction)
Here's my contrarian take: The "is Docker just a VM" question will be irrelevant in 5 years. WebAssembly and microVMs (Firecracker, gVisor) are blurring the lines. AWS Lambda runs containers-on-demand. Google's gVisor gives you container deployment with VM-like kernel isolation.
The question isn't "which one?" anymore. It's "which boundary do I need?"
Pick your boundaries intentionally. Your infrastructure — and your sleep schedule — will thank you.
Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.