Skip to main content
< All Topics

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.
FeatureDockerContainerdCRI-OPodman
Primary RoleFull Dev Suite (Build + Run)Invisible Runtime BackendK8s-Only RuntimeSecure Dev & Run Tool
ArchitectureClient-Server (Heavy Daemon)Daemon (Simplified)Daemon (Lightweight)Daemonless (Fork/Exec)
K8s SupportVia Dockershim (Deprecated)Native (via CRI plugin)Native (First-class citizen)Not for K8s orchestration
Rootless?Difficult setupSupportedSupportedYes (Default)
Best ForLocal DevelopmentCloud Managed K8s (GKE/EKS)OpenShift ClustersSecurity-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=podman works 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.

  1. 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-ONote: You can still use Docker to build images on your laptop or CI/CD pipelines.
  2. 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 root privileges, 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. Use crictl for debugging instead of docker CLI inside nodes.
  • 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 create and run containers inside it.

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):

Dockerfile Snippet
FROM golang:1.21 WORKDIR /app COPY . . RUN go build -o myapp main.go CMD [“./myapp”] # Result Size: 800MB (Because it includes the Go compiler!)

The Solution: Multi-Stage Build

We use two “stages”.

  1. Stage 1 (Builder): Has all the heavy tools to build the app.
  2. Stage 2 (Runner): A tiny, empty image where we copy only the final app.

✅ Good Example (Multi-Stage):

Multi-Stage Dockerfile Snippet
# STAGE 1: Build the app FROM golang:1.21 AS builder WORKDIR /app COPY . . RUN go build -o myapp main.go# STAGE 2: Run the app FROM alpine:latest WORKDIR /root/ # Copy ONLY the binary from Stage 1 COPY –from=builder /app/myapp . CMD [“./myapp”] # Result Size: 15MB (Magic!) 🚀

🔥 Pro Tip: Always use alpine versions 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:

Distroless Dockerfile Snippet
FROM gcr.io/distroless/static-debian11 COPY –from=build /app/my-app / CMD [“/my-app”]

Vulnerability Scanning

Never deploy an image without scanning it first. Vulnerabilities (CVEs) are found every day.

Top Tools:

  1. Trivy (Highly Recommended): Easy to use, finds OS and Library bugs.
  2. Clair: Used by many registries.
  3. 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.

Trivy Scan Snippet
# Install Trivy brew install trivy # or apt-get install trivy# Scan an image trivy image python:3.4

(Spoiler: You will likely see hundreds of vulnerabilities!)

Contents
Scroll to Top