Back to Docker: Images, Containers, Multi-Stage
Q10Question 10 of 10

Virtual Machine Versus Container With Respect to the Hypervisor

Key Concepts
  • A VM virtualizes hardware and runs a full guest OS with its own kernel on a hypervisor.
  • A container shares the host kernel and is isolated with namespaces (view) and cgroups (resource limits).
  • Containers are lighter (MBs vs GBs), start faster (ms vs seconds), and pack more densely per host.
  • VMs have stronger isolation because the hypervisor boundary contains even kernel-level compromises.
  • In practice, containers run inside VMs: Kubernetes nodes are VMs, giving hypervisor isolation at the node level.
  • Harden containers with non-root users, dropped capabilities, read-only filesystems, and seccomp profiles.

Definition

A VM runs a full guest OS on virtualized hardware via a hypervisor for strong isolation, while a container shares the host kernel using namespaces and cgroups for speed and density at the cost of a thinner boundary.
  • Virtual Machine – a hypervisor presents virtual hardware to each VM, and each VM runs its own complete guest OS including its own kernel.
  • Container – no guest OS, no virtual hardware; an isolated process on the host kernel, with namespaces for view isolation and cgroups for resource limits.
  • Hypervisor – software (KVM, VMware ESXi, Hyper-V) that manages virtual hardware; type 1 runs on bare metal, type 2 on a host OS.
  • Namespaces – Linux kernel feature giving each container its own view of processes (PID), network, mounts, users, and hostname.
  • Cgroups – Linux kernel feature capping and accounting CPU and memory per container.

Imagine the National Bank of India needs many independent offices. A VM is a separate self-contained building for each office, with its own foundation, plumbing, and power generator (its own kernel), sitting on a shared plot managed by a site manager (the hypervisor). A container is partitioning one large building into offices with walls and locked doors (namespaces) and a meter limiting each office's electricity (cgroups), all sharing one foundation (the host kernel). Containers are fast and dense, but a serious problem in the foundation affects everyone.

Understanding the Concepts

What is a Virtual Machine?

A VM virtualizes the hardware layer. The hypervisor presents virtual CPU, memory, disk, and network to each VM. Each VM boots a full guest operating system, including its own kernel, drivers, and system services.

DIAGRAM
  Physical Hardware
  ┌────────────────────────────────────┐
  │         Hypervisor (KVM/ESXi)      │
  ├──────────┬──────────┬──────────────┤
  │   VM 1   │   VM 2   │    VM 3      │
  │ Guest OS │ Guest OS │  Guest OS    │
  │ Kernel   │ Kernel   │  Kernel      │
  │ App      │ App      │  App         │
  └──────────┴──────────┴──────────────┘
  Each VM: full OS, own kernel, GBs, boots in seconds

What is a Container?

A container shares the host kernel. There is no guest OS and no virtual hardware. The container is an isolated process using Linux namespaces for view isolation and cgroups for resource limits.

DIAGRAM
  Physical Hardware
  ┌────────────────────────────────────┐
  │         Host OS + Kernel           │
  │         Container Runtime          │
  ├──────────┬──────────┬──────────────┤
  │  Ctr 1   │  Ctr 2   │   Ctr 3     │
  │  Libs    │  Libs    │   Libs      │
  │  App     │  App     │   App       │
  └──────────┴──────────┴──────────────┘
  Each container: app + libs only, MBs, starts in ms

How do VMs and containers compare?

| Aspect | Virtual Machine | Container |
|---|---|---|
| Virtualization | Hardware (CPU, memory, disk) | OS-level (namespaces, cgroups) |
| Guest OS | Full OS with its own kernel | None, shares host kernel |
| Image size | Gigabytes | Megabytes |
| Start time | Tens of seconds (OS boot) | Milliseconds (process start) |
| Density | Low (heavy per-VM overhead) | High (no kernel overhead) |
| Isolation | Strong (hypervisor boundary) | Weaker (shared kernel) |
| Resource overhead | High (guest kernel, drivers) | Low (only app + libs) |
| Use case | Multi-tenant, untrusted workloads | Microservices, fast scaling |

What are namespaces and cgroups?

Namespaces give each container its own isolated view. Cgroups enforce resource limits.

BASH
# PID namespace: container sees only its own processes
docker exec transfer-service-1 ps aux
# PID 1: java -jar app.jar
# The container cannot see processes from other containers or the host.

# Network namespace: container has its own network stack
docker exec transfer-service-1 ip addr
# Shows the container's own eth0 interface and IP, isolated from the host.

# Cgroups: cap memory and CPU
docker run -d --name transfer-service \
  --memory=512m --cpus=1.0 \
  registry.bank.local/transfer-service:1.2.0
# If the process exceeds 512 MB, the kernel OOM-kills it.
YAML
# Kubernetes: resource limits via cgroups
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: transfer-service
        image: registry.bank.local/transfer-service:1.2.0
        resources:
          requests: { memory: "256Mi", cpu: "250m" }
          limits:   { memory: "512Mi", cpu: "1000m" }

What is the isolation trade-off?

All containers on a host share one kernel. A kernel vulnerability or a container escape can potentially affect the host and sibling containers. A hypervisor is a stronger boundary.

BASH
# Container hardening: reduce the attack surface
docker run -d --name transfer-service \
  --user 1000:1000 \           # Non-root user
  --read-only \                 # Read-only filesystem
  --cap-drop ALL \              # Drop all Linux capabilities
  --security-opt no-new-privileges \  # No privilege escalation
  registry.bank.local/transfer-service:1.2.0
YAML
# Kubernetes: security context hardening
spec:
  containers:
  - name: transfer-service
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]

Why do containers run inside VMs in production?

In practice, Kubernetes worker nodes are VMs. This gives hypervisor isolation at the node level and container density within the node.

DIAGRAM
  Cloud Infrastructure
  ┌───────────────────────────────────────────┐
  │  VM (K8s Node 1)    VM (K8s Node 2)       │
  │  ┌─────┬─────┐     ┌─────┬─────┐         │
  │  │Ctr A│Ctr B│     │Ctr C│Ctr D│         │
  │  └─────┴─────┘     └─────┴─────┘         │
  │  Host Kernel        Host Kernel           │
  ├───────────────────────────────────────────┤
  │            Hypervisor (KVM)               │
  └───────────────────────────────────────────┘
  Hypervisor isolates VMs. Containers give density within VMs.

What about stronger container isolation?

For highly sensitive workloads, sandboxed runtimes give each container a thin VM boundary while keeping much of the speed.

BASH
# gVisor: user-space kernel intercepts syscalls
# Kata Containers: lightweight microVM per container
# Firecracker: Amazon's microVM used by AWS Lambda

# Kubernetes: RuntimeClass for sensitive workloads
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: sensitive-payment-pod
spec:
  runtimeClassName: gvisor   # Stronger isolation for payment workloads
  containers:
  - name: payment-service
    image: registry.bank.local/payment-service:1.0.0

What are common mistakes?

BASH
# WRONG: running containers as root with all capabilities.
docker run -d --privileged registry.bank.local/transfer-service:1.2.0
# A container escape gives root access to the entire host.

# CORRECT: non-root, dropped capabilities, read-only.
docker run -d --user 1000 --cap-drop ALL --read-only \
  registry.bank.local/transfer-service:1.2.0

What should a senior engineer know?

  • The shared-kernel model means a container's userspace can differ from the host (different distro base) but cannot run a different kernel or OS family.
  • For highly sensitive banking workloads, use microVM runtimes or dedicated node pools, accepting overhead for a stronger boundary.
  • Cgroups prevent one runaway service from starving neighbours by capping CPU and memory per container.
  • VMs remain the standard for mutually untrusted tenants. Containers are for trusted workloads within a VM boundary.

Visual Overview

DIAGRAM
  Virtual Machine:
  ┌────────────────────────────────────┐
  │         Hypervisor                 │
  ├──────────┬──────────┬──────────────┤
  │   VM 1   │   VM 2   │    VM 3      │
  │ Guest OS │ Guest OS │  Guest OS    │
  │ Kernel   │ Kernel   │  Kernel      │
  │ App A    │ App B    │  App C       │
  └──────────┴──────────┴──────────────┘
  Strong isolation, heavy, slow boot

  Container:
  ┌────────────────────────────────────┐
  │    Host OS + Kernel                │
  │    Namespaces + Cgroups            │
  ├──────────┬──────────┬──────────────┤
  │  Ctr A   │  Ctr B   │   Ctr C     │
  │  Libs    │  Libs    │   Libs      │
  │  App A   │  App B   │   App C     │
  └──────────┴──────────┴──────────────┘
  Weaker isolation, light, ms boot

  Production: containers inside VMs
  ┌──── VM (K8s Node) ────┐
  │ ┌─────┐ ┌─────┐       │
  │ │Ctr A│ │Ctr B│ ...   │  ← Container density
  │ └─────┘ └─────┘       │
  │    Host Kernel         │
  └────────────────────────┘  ← VM isolation

Key Takeaway

The difference comes down to what each virtualizes and where the isolation boundary sits. A VM virtualizes hardware: a hypervisor presents virtual CPU, memory, and disk, and each VM boots its own complete guest OS with its own kernel. A container does not virtualize hardware and has no guest OS; it is an isolated process on the host kernel, with namespaces for view isolation and cgroups for resource limits.

That architectural difference drives every practical consequence. VMs are heavy (GBs), boot in seconds, and spend significant memory on the guest OS. Containers are light (MBs), start in milliseconds, and pack far more densely per host. The trade-off is isolation: a hypervisor is a strong boundary that contains even kernel-level compromises, while containers share one kernel, making the boundary thinner.

In practice, containers run inside VMs. Each Kubernetes worker node is a VM, giving hypervisor isolation at the node level and container density within the node. For highly sensitive banking workloads, microVM runtimes or dedicated node pools provide a stronger boundary per container.

Remember one sentence: a VM runs a full guest OS on virtualized hardware for strong isolation, while a container shares the host kernel for speed and density.

---

Share
Use ← → arrow keys to navigate