Container Fundamentals
Welcome to Chapter 2! In the last chapter, we learned how Linux makes containers possible. Now, we will look at the tools that actually create them.
Most people think “Container = Docker”. But in 2026, that is wrong. Docker is just one player in a big team. To master Kubernetes, you need to understand the “Container Wars” and how to build images that are small, fast, and secure.
The Container Runtime War
Docker vs. Containerd vs. CRI-O vs. Podman
Think of container runtimes as driving a car.
Imagine you want to go for a drive.
- Docker is like a Luxury SUV. It has leather seats, a high-end music system, GPS, and climate control. It does everything for you, but it is heavy and consumes a lot of fuel.
- Kubernetes is a Fleet Manager. It doesn’t care about the music system or leather seats; it just needs the engine to move the cargo.
- Containerd is the Engine taken out of the luxury SUV. It is powerful and reliable but strips away the fancy dashboard.
- CRI-O is a Custom-Built Racing Engine. It was built from scratch specifically for the Fleet Manager (Kubernetes) to be as lightweight as possible.
- Podman is like a Self-Driving Electric Car. It doesn’t need a central driver (Daemon) constantly running in the background. You just get in and go.
–
Here are the quick one-liners you need to remember for rapid discussions:
- Docker: The “Swiss Army Knife” of containers great for developers on laptops but too heavy for modern Kubernetes clusters.
- Containerd: The “Standard Industrial Engine” graduated from Docker to become the industry standard runtime for Kubernetes (EKS, AKS, GKE).
- CRI-O: The “Kubernetes Purist” lightweight runtime built only for Kubernetes, largely used in Red Hat OpenShift.
- Podman: The “Secure Rebel” a daemonless, rootless alternative to Docker that is command-line compatible (
alias docker=podman).
- OCI (Open Container Initiative): The rulebook that ensures an image built by Docker can run on Podman or CRI-O.
- CRI (Container Runtime Interface): The “plug” that allows Kubernetes to talk to different runtimes like Containerd or CRI-O.
- Dockershim: The bridge Kubernetes used to talk to Docker. Note: This was removed in Kubernetes v1.24.
| Feature | Docker | Containerd | CRI-O | Podman |
| Primary Role | Full Dev Suite (Build + Run) | Invisible Runtime Backend | K8s-Only Runtime | Secure Dev & Run Tool |
| Architecture | Client-Server (Heavy Daemon) | Daemon (Simplified) | Daemon (Lightweight) | Daemonless (Fork/Exec) |
| K8s Support | Via Dockershim (Deprecated) | Native (via CRI plugin) | Native (First-class citizen) | Not for K8s orchestration |
| Rootless? | Difficult setup | Supported | Supported | Yes (Default) |
| Best For | Local Development | Cloud Managed K8s (GKE/EKS) | OpenShift Clusters | Security-focused Devs |
–
1. Docker (The Celebrity)
- What it is: A complete suite (Engine + CLI + API + Build tools).
- History: It started the revolution.
- The Problem: It’s “heavy.” It has features Kubernetes doesn’t need.
- Current Status: Kubernetes actually removed support for the “Docker Shim” in version 1.24. K8s no longer uses Docker directly!
2. Containerd (The Worker)
- What it is: This is the engine inside Docker. Docker stripped out its user interface and donated the core engine to the community.
- Relation to K8s: Kubernetes uses Containerd directly now. It skips the heavy Docker interface.
- Why use it? It is lightweight, fast, and stable.
3. CRI-O (The Kubernetes Specialist)
- What it is: A runtime built specifically for Kubernetes.
- Name: “Container Runtime Interface – OCI”.
- Why use it? It is extremely lightweight. It does only what Kubernetes asks. If you use OpenShift (Red Hat), you are using CRI-O.
4. Podman (The Secure Rebel)
- What it is: A Docker alternative from Red Hat.
- The Key Difference: Docker requires a “Daemon” (a background process running as Root). Podman is Daemonless. You can run containers as a normal user.+1
- Command: It is compatible!
alias docker=podmanworks perfectly.
–
In the early days, Docker was the only game in town. It combined the tools to build images (creating the container) and run images (executing the container).
However, as the industry matured, we realized we didn’t always need the whole package.
- The Split: Docker eventually separated its core execution logic into a separate project called Containerd. This allows other tools to use the engine without the heavy Docker UI.
- The Standard: The Open Container Initiative (OCI) was formed to standardize how containers are formatted. This is why you can build an image in Docker and run it in Podman.
For an architect, the choice of runtime impacts security posture and cluster performance.
- The Dockershim Deprecation (K8s v1.24+):
- Previously, Kubernetes had to maintain a messy code bridge called “Dockershim” to talk to Docker.
- Now, Kubernetes speaks CRI (Container Runtime Interface) directly.
- Impact: You cannot use Docker Engine as the underlying runtime for K8s clusters anymore. You must use Containerd or CRI-O. Note: You can still use Docker to build images on your laptop or CI/CD pipelines.
- Attack Surface Reduction:
- CRI-O is often favored in high-security environments (like banking or government) because it has a smaller code footprint than Containerd. Less code = fewer potential bugs to exploit.
- Podman introduces the concept of “Fork/Exec” model. Unlike Docker, which relies on a continuously running background process (Daemon) with
rootprivileges, Podman starts containers as child processes of the user. This significantly reduces the risk of privilege escalation attacks.
–
Key Characteristics
- Daemon-based (Docker/Containerd): A central program runs in the background managing all containers. If the Daemon crashes, all containers might lose management capabilities.
- Daemonless (Podman): Each container is independent. If one crashes, the others are unaffected.
- CRI-Compatible: Must be able to receive instructions from the Kubernetes
kubelet.
Use Case
- Docker: Best for a developer’s MacBook or Windows laptop. The “Docker Desktop” experience is still unbeatable for ease of use.
- Containerd: The default choice for almost all general-purpose Kubernetes clusters (AWS EKS, GKE).
- CRI-O: Best for environments strictly sticking to Red Hat ecosystems (OpenShift) or requiring minimal footprints.
- Podman: Best for HPC (High-Performance Computing) and shared servers where users should not have root access.
Benefits
- Modularity: You can swap engines without breaking applications.
- Security: Moving away from the monolithic Docker daemon reduces the “Blast Radius” of a hack.
- Performance: Stripping away the UI and build tools (using CRI-O/Containerd) saves RAM and CPU on production servers.
Limitations
- Docker: Cannot be used natively in K8s anymore. Requires root privileges which is a security risk.
- Podman: Since it has no daemon, tools that expect a socket (like some older monitoring agents) might fail or require specific configuration (
podman.socket). - CRI-O: It is purely a runtime. It has no CLI for developers to “build” images easily like Docker does.
Common Issues and Solutions
- Issue:My Docker commands don’t work in the new Kubernetes cluster!
- Solution: You are likely trying to mount the Docker socket (
/var/run/docker.sock) which no longer exists. Usecrictlfor debugging instead ofdockerCLI inside nodes.
- Solution: You are likely trying to mount the Docker socket (
- Issue:Podman containers can’t talk to each other.
- Solution: Without a daemon, networking is handled differently. You must explicitly create a pod:
podman pod createand run containers inside it.
- Solution: Without a daemon, networking is handled differently. You must explicitly create a pod:
- Docker: https://docs.docker.com/
- Containerd: https://containerd.io/docs/
- CRI-O: https://cri-o.io/
- Podman: https://podman.io/docs/
- Kubernetes CRI: https://kubernetes.io/docs/concepts/architecture/cri/
Lab The Container Runtime
Quiz The Container Runtime
Writing Optimized Dockerfiles
Writing Dockerfile
(The Art of Multi-Stage Builds)
A beginner writes a Dockerfile and gets a 1 GB image. A pro writes the same app and gets a 50 MB image. How? By using Multi-Stage Builds.
The Problem: The “Fat” Image
When you build a Go or Java app, you need compilers (Maven, GCC, Go tools). But to run the app, you only need the binary file. You don’t need the compiler in production.
❌ Bad Example (Single Stage):
The Solution: Multi-Stage Build
We use two “stages”.
- Stage 1 (Builder): Has all the heavy tools to build the app.
- Stage 2 (Runner): A tiny, empty image where we copy only the final app.
✅ Good Example (Multi-Stage):
🔥 Pro Tip: Always use
alpineversions for your base image (e.g.,python:3.9-alpine) to save massive space.
Image Security: Hardening Security for Containers
(Distroless & Scanning)
Security isn’t an afterthought; it starts at the Dockerfile.
The Threat: “Shell Access”
If a hacker gets into your container, the first thing they do is open a terminal (/bin/sh). If your container has bash, curl, and wget installed, you have given the hacker a toolkit to attack your network.
The Solution: Distroless Images
Google created Distroless images.
- They contain ONLY your application and its dependencies.
- No Package Manager (
apt,yum). - No Shell (
bash,sh). - No Text Editor (
vim,nano).
If a hacker exploits your app, they cannot spawn a shell because there is no shell!
Example:
Vulnerability Scanning
Never deploy an image without scanning it first. Vulnerabilities (CVEs) are found every day.
Top Tools:
- Trivy (Highly Recommended): Easy to use, finds OS and Library bugs.
- Clair: Used by many registries.
- Docker Scan: Built into Docker Desktop (
docker scan my-image).
🧪 Quick Lab: Run a scan on an old image and see how many “High” severity bugs it has.
(Spoiler: You will likely see hundreds of vulnerabilities!)