How Container Images Work
How Container Images Work
A container image is built in layers. Each instruction in a Dockerfile creates a new layer. Layers are cached, so rebuilding is fast when only a few layers change.
┌─────────────────────────┐
│ Application Code │ ← Your app layer
├─────────────────────────┤
│ Dependencies (npm, │ ← Libraries layer
│ pip, go modules) │
├─────────────────────────┤
│ Runtime (Node, Python │ ← Runtime layer
│ Go binary) │
├─────────────────────────┤
│ Base OS (alpine, │ ← Base image layer
│ debian, scratch) │
└─────────────────────────┘
Image Layers in Detail
Every FROM, RUN, COPY, and ADD instruction creates a new layer. Other instructions (ENV, EXPOSE, CMD) only add metadata and don’t create filesystem layers.
Layer 4: COPY . . (app code — changes often)
Layer 3: RUN pip install -r req.txt (dependencies — changes sometimes)
Layer 2: COPY requirements.txt . (dep file — changes sometimes)
Layer 1: FROM python:3.12-slim (base image — rarely changes)
Key insight: Docker uses a layer cache. If a layer hasn’t changed, Docker reuses it from cache instead of rebuilding. This is why you copy dependency files (like package.json or requirements.txt) before copying your full application code — the dependency layer stays cached unless dependencies change.
Image Naming Convention
registry/repository:tag
| Part | Description | Example |
|---|---|---|
| Registry | Where the image is stored | docker.io, gcr.io, registry.example.com |
| Repository | Image name (optionally with namespace) | library/nginx, team/my-app |
| Tag | Version identifier | 1.27, latest, sha-abc123 |
Examples:
nginx:1.27— Docker Hub, nginx repo, tag 1.27docker.io/library/nginx:latest— fully qualified namegcr.io/my-project/api:v2.1— Google Container Registrymy-registry.com/team/app:sha-abc123— custom registry with commit SHA
Exam tip: Always use specific tags (like nginx:1.27) instead of latest. Using latest makes deployments unpredictable.
Image Digests
A digest is a SHA256 hash of the image manifest, providing an immutable reference:
nginx@sha256:abc123def456...
Unlike tags (which can be moved to point to different images), digests always reference the exact same image content.
How Images Are Stored and Distributed
Developer Registry Kubernetes Node
┌──────────┐ push ┌──────────────┐ pull ┌──────────────┐
│ docker │ ────────→ │ Docker Hub / │ ────────→ │ containerd / │
│ build │ │ ECR / GCR │ │ CRI-O │
└──────────┘ └──────────────┘ └──────────────┘
- Build — The image is created locally from a Dockerfile
- Push — The image is uploaded to a registry
- Pull — Kubernetes (via the container runtime) downloads the image to the node
- Run — The container runtime creates a container from the image
Image Size Matters
Smaller images are better for several reasons:
| Benefit | Why |
|---|---|
| Faster pulls | Less data to download from the registry |
| Faster deployments | Pods start quicker, especially on cold nodes |
| Less storage | Saves disk space on nodes |
| Smaller attack surface | Fewer packages = fewer vulnerabilities |
Common base image sizes:
| Base Image | Size |
|---|---|
ubuntu:22.04 |
~77 MB |
debian:bookworm-slim |
~74 MB |
alpine:3.19 |
~7 MB |
gcr.io/distroless/static |
~2 MB |
scratch |
0 MB |