caduh

Containers 101 — what they are and why they matter

3 min read

A no-jargon primer on containers: how they isolate processes, how images/layers work, and what Docker/Kubernetes actually do.

TL;DR

  • A container packages your app and its dependencies to run as an isolated process on a host sharing the OS kernel.
  • A virtual machine (VM) packages a full OS with virtualized hardware—heavier but with stronger isolation and its own kernel.
  • Containers: fast start (ms–s), small images, high density, great for microservices/CI/CD.
  • VMs: strong isolation, any kernel/OS, good for untrusted/privileged or system-level workloads.
  • Value: portability, repeatable deploys, resource efficiency, and dev→prod parity.

The mental model (in one minute)

Process isolation  +  Filesystem snapshot  +  Network namespace  +  Resource limits
            │                 │                     │                        │
        (PID/ns)        (image layers)           (bridge)                 (cgroups)
  • A container is just a process with its own view of the world (PID, mount, network namespaces) and resource limits (cgroups).
  • An image is a stack of read‑only layers; a container adds a thin, writable layer on top.
  • The host kernel is shared; there’s no guest kernel like in a VM.

VM vs Container (quick compare)

| Aspect | Container | Virtual Machine | |---|---|---| | Isolation unit | Process (namespaces/cgroups) | Full OS (hypervisor) | | Kernel | Shared with host | Own guest kernel | | Boot/start time | ms–seconds | seconds–minutes | | Image size | 10s–100s MB | GBs | | Density | High (many per host) | Lower | | Portability | Great (OCI images) | Good (images/AMIs), heavier | | Security | Good, but shared kernel; harden config | Stronger isolation boundary | | Best for | Microservices, CI, ephemeral tasks, autoscaling | Strong isolation, legacy OS, kernel-specific workloads |


Core building blocks

  • Image: immutable snapshot (layers). Built from a Dockerfile (or Buildpacks).
  • Container runtime: containerd/runc (Docker uses these under the hood) — OCI standard compliant.
  • Registry: where images live (Docker Hub, GHCR, ECR, GCR).
  • Orchestration: Docker Compose for local/dev; Kubernetes/ECS/Nomad for fleets.

Minimal, real-world examples

A tiny Dockerfile (Node.js)

# 1) smaller base for prod
FROM node:20-alpine AS base

# 2) install deps separately for better caching
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# 3) copy app code
COPY . .

# 4) run as non-root
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Build & run

docker build -t myapp:latest .
docker run -p 3000:3000 --rm myapp:latest

Compose: app + Postgres

version: "3.9"
services:
  api:
    build: .
    ports: ["3000:3000"]
    environment:
      DATABASE_URL: postgres://postgres:postgres@db:5432/app
    depends_on: [db]
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: postgres
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:

Why containers feel faster & cheaper

  • No guest OS → fewer resources per instance.
  • Layer caching → rebuilds push only changed layers.
  • Immutable images → “works on my machine” becomes works anywhere.
  • Horizontal scale → start/stop containers quickly to match load.
  • Dev/Prod parity → same image in CI, staging, and prod.

Persistence & networking (gotchas)

  • Containers are ephemeral: store state on volumes or external services (managed DBs, object storage).
  • Networking defaults to a bridge; expose ports with -p 8080:80. Compose/K8s add service discovery.
  • Logs go to stdout/stderr; ship them via drivers or sidecars.

Security basics (must-do)

  • Don’t run as root: set USER in Dockerfile.
  • Use small/base images (Alpine, distroless) and scan for CVEs.
  • Keep secrets out of images (use env vars/secret managers).
  • Apply resource limits (--cpus, --memory) and read‑only filesystems when possible.
  • Patch regularly; rebuild from updated bases.

When to pick VMs instead

  • You need a different kernel/OS than the host (e.g., Windows kernel apps on Linux hosts).
  • Hard multi‑tenant isolation or regulatory separation.
  • System services that expect full OS control (kernels, device drivers).

Quick command cheat sheet

docker ps                     # list running containers
docker images                 # list images
docker logs -f <container>    # tail logs
docker exec -it <container> sh  # shell into a container
docker compose up -d          # start services
docker system prune -f        # cleanup dangling images/containers

One‑minute decision guide

  • Stateless web/API, microservices, CI jobs?Containers.
  • Per-tenant isolation, custom kernel/OS, heavy system access?VMs.
  • Mixed? → Run apps in containers on VMs; use the best of both.