Lesson 4: Docker & Containerization Primitives
π§ The Concept (Explain Like I'm 5)
In the 1950s, cargo ships took days to load because cargo was loose: barrels of wine, sacks of grain, crates of tools. If a barrel broke, everything got soaked.
Then came the Standard Shipping Container. Regardless of whether it carries wine or cars, the container has standard dimensions and locks onto any crane, truck, train, or ship.
Docker is shipping containers for software: * It packages your code, runtime, system libraries, and configs into a single immutable artifact. * If it runs on your laptop, it runs identically on an AWS EC2 instance, an Azure VM, or a Kubernetes cluster.
π’ The Enterprise Context (Why Platform Architects Care)
- "It works on my machine" is dead: Containers guarantee environmental parity from local dev to staging to production.
- Resource Efficiency: Virtual Machines require an entire guest operating system (consuming gigabytes of RAM). Containers share the host Linux kernel, booting in milliseconds and using minimal memory.
- Foundation for Kubernetes: Kubernetes does not manage code; it exclusively manages containerized workloads.
πΊοΈ Visual Architecture: VM vs. Container
flowchart TD
subgraph VMArchitecture ["Traditional Virtual Machine (Heavy)"]
direction TB
VM_App["App A"] --> VM_Bins["Bins / Libs"]
VM_Bins --> VM_GuestOS["Guest OS (Ubuntu/RHEL ~2GB+)"]
VM_GuestOS --> Hypervisor["Hypervisor (ESXi / KVM)"]
Hypervisor --> HostOS_VM["Host OS / Bare Metal"]
end
subgraph ContainerArchitecture ["Container Engine (Lightweight)"]
direction TB
C_App1["App A"] --> C_Bins1["Bins / Libs"]
C_App2["App B"] --> C_Bins2["Bins / Libs"]
C_Bins1 --> DockerEngine["Container Engine (Docker / containerd)"]
C_Bins2 --> DockerEngine
DockerEngine --> LinuxKernel["Shared Host Linux Kernel (cgroups & namespaces)"]
LinuxKernel --> BareMetal["Host Hardware"]
end
ποΈ How Docker Builds Images (Layer Caching)
Every command in a Dockerfile creates a read-only layer. Docker caches layers to make builds lightning-fast:
flowchart BT
L1["FROM python:3.11-slim (Base OS Layer)"] --> L2["WORKDIR /app"]
L2 --> L3["COPY requirements.txt ."]
L3 --> L4["RUN pip install -r requirements.txt (Dependency Layer)"]
L4 --> L5["COPY . . (Application Code Layer)"]
L5 --> L6["USER 10001 (Security: Non-Root User)"]
L6 --> L7["CMD ['python', 'app.py'] (Runtime Entrypoint)"]
Enterprise Dockerfile Best Practice: Layer Ordering
Notice that COPY requirements.txt and RUN pip install happen before COPY . ..
Because source code changes frequently but dependencies change rarely, Docker reuses the cached pip install layer on every build, dropping CI build times from 5 minutes to 3 seconds!
π Container Networking & Port Forwarding
A container runs in its own private network namespace. To reach it from outside, you must map a host port to the container port:
flowchart LR
Client["User Browser<br/>http://localhost:8080"] -->|"Hits Host Port 8080"| HostPort["Host Port :8080"]
HostPort -->|"iptables / NAT forward (-p 8080:80)"| ContPort["Container Port :80"]
ContPort --> Nginx["NGINX Process inside Container"]
π» Essential Docker Commands
# 1. Build an image with a specific tag
docker build -t my-microservice:v1.0.0 .
# 2. Run container in detached mode with port mapping and environment variables
docker run -d -p 8080:80 --name webapp -e ENV=production my-microservice:v1.0.0
# 3. View running containers and resource consumption
docker ps
docker stats
# 4. Open a shell inside a running container to debug
docker exec -it webapp /bin/sh
# 5. Inspect container logs
docker logs --tail 100 -f webapp
# 6. Stop and remove container
docker stop webapp && docker rm webapp
π Knowledge Check
Question 1
Why is running a container as the default root user considered a high-severity security risk in enterprise Kubernetes clusters?
Question 2
Explain why a container image built with FROM alpine or python:slim is preferred over FROM ubuntu:latest in enterprise DevSecOps pipelines.