Frontend Labs
⋯

PHASE 3 — Containerization: Docker and Kubernetes

Everything from here builds directly on Phases 1 and 2. A container is not a new kind of virtual computer — it's an ordinary Linux process, given its own view of the filesystem, its own process tree, its own network stack, and a capped slice of resources, using EXACTLY the OS mechanisms you already know: namespaces, cgroups, and the filesystem model. If a container ever does something confusing, the answer is almost always "go back to Phase 1's mental model and apply it here."

Going further: this phase gets you to "I understand containers and Kubernetes". Docker & Kubernetes — The Real-Life Field Guide continues to production: hardened images, probes and graceful shutdown, autoscaling, OpenTelemetry observability, GitOps, canary releases and disaster recovery, built as one system in a Linux lab VM.

Part 14 — Container fundamentals

Every part so far was one OS running many processes with the illusion of isolation (Part 1's lie, again). A container is that same illusion, turned into a deliberate, hardened feature. This part shows that namespaces and cgroups are the real mechanism behind it — not magic, and nothing you haven't already learned the pieces of.

Chapter 44 — What a container actually is (namespaces + cgroups + a filesystem)

In one sentence

A container is a normal Linux process running with its own PID namespace (so it sees only its own processes), its own network namespace (Chapter 37's exact model, isolated), a cgroup capping its resource usage (Chapter 43), and its own root filesystem — no new kernel feature invented specifically for "containers" at all.

Why this matters

"How is a container different from a process" and "why did my container get OOM-killed" both stop being mysterious the moment you see containers as a COMPOSITION of things you already learned in Phase 1, not a separate technology.

How it actually works

   FOUR INGREDIENTS, each one YOU ALREADY KNOW:

     1. PID NAMESPACE      the container's main process becomes PID 1
                          INSIDE its own namespace (Chapter 6's process
                          tree, but the container gets its OWN, private
                          root of that tree) -- it cannot see, and
                          cannot signal (Chapter 20), processes outside
                          its namespace.

     2. NETWORK NAMESPACE   its own network interfaces, IP address, and
                          routing table (Chapter 37) -- including its
                          own, SEPARATE `localhost`, exactly as Chapter
                          37's real-world example previewed.

     3. MOUNT NAMESPACE / ROOT FILESYSTEM   its own view of the
                          filesystem (Chapter 24's hierarchy), typically
                          built from a container IMAGE (Chapter 46) --
                          so it can have its OWN `/etc`, its own
                          installed packages, entirely separate from the
                          host's, even though it's ultimately running on
                          the SAME kernel.

     4. CGROUP             a resource limit (CPU, memory -- Chapters 8,
                          10, 13, 43) applied to the container's
                          process(es) as a group, enforced by the
                          kernel, not politely requested.

   PUT TOGETHER: a container process, from the KERNEL'S perspective, is
   still just an ordinary process -- `ps aux` on the HOST machine shows
   it, right alongside every other process, with its own real PID in the
   host's OWN, top-level PID namespace. It's just been given a
   deliberately RESTRICTED VIEW of the system (can't see other
   namespaces' processes/network) and a CAPPED SLICE of resources
   (cgroups) -- fundamentally the same isolation idea as Chapter 1's
   "the OS as a resource manager" and Chapter 10's virtual memory, just
   composed at a coarser, whole-process-environment level.

Real-world example

   Docker (first publicly introduced by Solomon Hykes at a PyCon
   lightning talk in 2013) is often, inaccurately, credited with
   "inventing containers" -- the real, well-documented history is more
   interesting and more directly illustrates this chapter's point: the
   underlying Linux kernel mechanisms Docker relies on -- namespaces
   (introduced incrementally into the kernel starting in the early-to-
   mid 2000s) and cgroups (merged into the mainline kernel in 2007,
   developed originally at Google for exactly this resource-isolation
   purpose) -- PREDATED Docker by years. LXC (Linux Containers), an
   earlier project, already used these SAME primitives directly to
   provide container-like isolation before Docker existed.
   What Docker actually, genuinely contributed -- and this is well
   documented across its own project history and countless retrospective
   engineering writeups -- was a dramatically better USER EXPERIENCE: a
   simple, portable IMAGE FORMAT (Chapter 46) that could be built once
   and run identically anywhere, a straightforward CLI, and a
   registry/distribution model (Chapter 52) for sharing images. Docker's
   genuine innovation was PACKAGING AND ERGONOMICS around existing
   kernel primitives, not the isolation mechanism itself -- which is
   exactly why this chapter can teach you "what a container is" using
   ONLY concepts from Phase 1: the primitives really are that
   fundamental, and really did exist before the word "container" became
   an industry-wide household term.

Try it yourself

# See a container process from the HOST's perspective -- it's just a
# normal process (requires Docker -- if not installed yet, install it
# now: get.docker.com has the official install script, or use your
# distro's package manager)
docker run -d --name pidtest nginx
docker inspect --format '{{.State.Pid}}' pidtest   # the REAL, host-
                                                    # level PID
ps -p $(docker inspect --format '{{.State.Pid}}' pidtest)  # there it
                                                            # is, in
                                                            # your
                                                            # NORMAL
                                                            # host `ps`
                                                            # output

# See the PID namespace difference: PID 1 inside vs. outside
docker exec pidtest ps aux    # inside the container, nginx is PID 1
ps -p $(docker inspect --format '{{.State.Pid}}' pidtest)  # outside,
                                                            # it's some
                                                            # other,
                                                            # larger PID

# See the cgroup this container was actually assigned
docker inspect --format '{{.HostConfig.Memory}}' pidtest
cat /sys/fs/cgroup/system.slice/docker-*.scope/memory.max 2>/dev/null | head -1 || \
  echo "(cgroup path varies by cgroup version/driver -- informational)"

docker rm -f pidtest

Build it in Go

The best way to stop thinking of containers as magic is to build one. Chapter 80 does it in about 150 lines of Go: new UTS, PID, mount, IPC, and network namespaces; chroot into a BusyBox filesystem; a private /proc; and a cgroup v2 limit that stops a fork bomb at 20 processes. For how attackers break out of containers, and how to stop them, see Security Engineering in Depth, Chapter 15.

Common mistakes

  • Thinking a container is "a lightweight VM." Chapter 45 makes this precise, but the short version: there's no virtualised hardware, no separate kernel — it's a specially-isolated ordinary process, sharing the HOST's kernel directly.
  • Assuming "container" is a Linux kernel feature you can point to. There's no container syscall or kernel object — it's a COMPOSITION of namespaces, cgroups, and a filesystem, orchestrated by tooling (Docker, containerd, etc.), exactly as this chapter describes.
  • Forgetting the container shares the HOST's kernel. A kernel-level vulnerability or a container escape (a real, documented risk category, covered in this wiki's security guides) can cross this isolation boundary — it's strong, but it is not the same guarantee as separate hardware virtualization.

Check yourself

  1. Name the four Linux mechanisms that, composed together, make a container.
  2. Why does ps aux on the HOST show a container's processes too?
  3. What did Docker actually invent, versus what already existed in the Linux kernel before it?

(Answers: Appendix E.)

Further reading

  • Talk: Solomon Hykes' original 2013 Docker introduction (search "Docker PyCon 2013 lightning talk") — genuinely worth watching for the real history.
  • Reference: man 7 namespaces, man 7 cgroups, man 7 pid_namespaces.
  • Article: search "containers are just Linux processes" — this exact framing has been written up excellently, multiple times, by various container-runtime engineers.

Generated from real-life-os-guide.md · 8 Oct 2026 16:36