Production Concerns

VMs & Containers

● Beginner ⏱ 10 min read production

Virtual machines and containers are two approaches to running isolated workloads on shared hardware. Both let you run multiple applications on the same physical server without interference. They achieve isolation differently — VMs virtualize hardware; containers virtualize the operating system. Understanding the distinction matters when choosing infrastructure, sizing workloads, and designing deployment pipelines.

Virtual Machines

A virtual machine (VM) is a complete emulation of a physical computer. A hypervisor — software that sits between the hardware and the VMs — creates and manages these virtual environments. Each VM gets its own virtual CPU, memory, disk, and network interface.

Two types of hypervisors:

Each VM runs its own full operating system — its own kernel, device drivers, system libraries, and application stack. A VM image for a Linux web server might be 10–20 GB. Boot time is typically 30–60 seconds, since an entire OS must initialize.

VMs virtualize hardware (each has its own OS); containers share the host kernel (isolated via namespaces and cgroups)

Containers

A container is a lightweight, isolated process that shares the host machine’s operating system kernel. Containers don’t virtualize hardware — they use Linux kernel features to create the illusion of isolation:

Because containers share the host kernel, they have no OS boot sequence. A container starts in milliseconds — it’s just launching a process. A Docker container image for a web server might be 50–200 MB, compared to 10–20 GB for a VM image.

How Docker Works

Docker is the most widely used container runtime. Its architecture has three components:

When you run docker run nginx:

  1. The CLI sends a request to dockerd.
  2. dockerd pulls the nginx image from Docker Hub if not cached locally.
  3. dockerd asks containerd to create a container from the image.
  4. containerd sets up namespaces and cgroups, mounts the image layers, and starts the nginx process.
  5. The container is running — nginx is now an isolated process on the host.

Images and Layers

A Docker image is built from layers. Each instruction in a Dockerfile creates a new layer:

FROM ubuntu:22.04         # Layer 1: base Ubuntu filesystem
RUN apt-get install nginx # Layer 2: nginx binary and dependencies
COPY ./app /var/www/html  # Layer 3: your application code
CMD ["nginx", "-g", "daemon off;"]  # metadata (no new layer)

Layers are content-addressed and cached. If layer 1 and 2 haven’t changed, rebuilding after modifying your app code only creates a new layer 3. Layers are shared between containers — if 10 containers use the same Ubuntu base image, that base layer exists once on disk.

When a container runs, Docker adds a thin writable layer on top of the read-only image layers. All writes go to this container layer. When the container is deleted, the writable layer is deleted — the underlying image layers are unchanged. This is why containers should treat their filesystem as ephemeral; persistent data must be stored in volumes (host directory mounts or Docker-managed volumes).

VM vs Container

Virtual MachineContainer
Isolation levelFull hardware virtualization — own kernel, OSProcess-level — shared kernel, isolated namespaces
Startup time30–60 seconds (OS boot)Milliseconds (process start)
Image sizeGigabytesMegabytes
Density10–100s of VMs per host1000s of containers per host
Security boundaryStrong — kernel compromise requires hypervisor escapeWeaker — kernel vulnerabilities affect all containers
OS flexibilityAny OS — Windows, Linux, different kernel versionsMust match host kernel type (Linux containers need Linux host)
OverheadHigher — full OS per VMNear-native — minimal overhead
Use caseStrong isolation, multi-tenant cloud, different OS requirementsMicroservices, CI/CD, high-density workloads
💡
Containers Run Inside VMs in the Cloud

In cloud environments, you typically run containers inside VMs — not directly on bare metal. An EC2 instance is a VM; you run Docker containers on that VM. This gives you the cloud’s VM-level isolation between tenants, plus containers’ density and fast startup within your own VM. Managed Kubernetes services (EKS, GKE, AKS) provision VMs as worker nodes and run containers on them.

Container Orchestration

Running containers on a single host is straightforward. Running thousands of containers across hundreds of hosts — with load balancing, health checks, rolling deploys, auto-scaling, and service discovery — requires an orchestrator.

Kubernetes is the dominant container orchestrator. It manages:

Kubernetes abstracts the underlying infrastructure — you declare desired state (3 replicas of this container, limit to 500m CPU) and Kubernetes reconciles reality to match. This declarative model is what makes large-scale container operations manageable.

Design Considerations