What’s up, guys! Welcome — or welcome back — to the log. In our last log, we covered Chapter 3 of the Docker Deep Dive book. Today, we’re diving into Chapters 4 and 5. Chapter 4 introduces some high-level concepts around Docker images and containers, while Chapter 5 pulls back the curtain on what Docker really is.

Before I even touched Chapters 4 and 5, I actually paused the book and went down a container rabbit hole. I wanted to understand what containers are — independent of Docker.

What Is a Container (Outside of Docker)

Let’s strip “containers” away from Docker for a second, because people use the words interchangeably, and they’re not the same thing. Imagine you’re on a Linux server and launch something like VS Code. That action starts a process — a program loaded into memory and executed by the CPU.

At its core, a container is just a process. But it’s a process with fences — rules enforced by the Linux kernel that isolate it from the rest of the system. So what makes a container different from just any process? It comes down to a handful of Linux features:

  • Namespaces isolate the process’s view of the system (its own PID tree, mounts, network, etc.).
  • Cgroups limit and control resource usage (CPU, memory, etc.).
  • chroot/mount namespaces restrict which part of the filesystem the container sees.
  • Capabilities drop unnecessary root privileges inside the container.
  • Seccomp filters or blocks dangerous system calls.
  • UnionFS (optional) adds layered filesystem support.

Put all of that together and you get an isolated, lightweight process that can still run child processes — basically the apps you install inside it. That’s what a container is: an isolated Linux process built with native kernel features. And here’s the wild part — Linux already has all of this built in. Container tooling (like Docker or LXC) just makes it easier to use.

Docker vs. LXC (Container Runtimes)

So the next question is, what do tools like Docker and LXC actually add on top? Both are wrappers around the container features already in Linux, but they approach them differently.

Docker is designed to run one application per container. It’s meant to package and isolate an app (like NGINX or Postgres), and it handles the hard stuff: networking, volumes, startup, teardown. It’s focused on apps, not full systems.

LXC, on the other hand, acts more like a lightweight VM. You can install Ubuntu in it, boot it, SSH in, run multiple apps, and treat it like a mini operating system.

The takeaway? Don’t treat Docker containers like VMs. They’re not meant to run an entire OS. But with LXC, you can. Technically, you could create a container manually using Linux commands, but it’s tedious. That’s why Docker and LXC blew up — they make containers usable. Alright, rabbit hole over. Now that we’ve separated containers from the tools built to manage them, let’s swing back to the book.

Chapter 4: High-Level View of Docker

Chapter 4 gives us a surface-level view of Docker — just enough to set the stage. It frames Docker from two perspectives. On the Ops side, it’s about managing Docker: installing it, pulling images, starting containers, checking logs. On the Dev side, it’s about writing Dockerfiles, cloning repos, building images, and spinning up apps.

This is also where images are introduced. Images are essentially snapshots of a complete app environment — the app plus all its dependencies.

I’m not doing a hands-on demo for this chapter, though. It felt more like a preview of what’s coming later, and the big takeaway is simple: Docker can be approached from both the Dev and Ops angles — and as we move forward, we’ll be wearing both hats.

Chapter 5: The Docker Engine

Now this chapter is where things get good. Chapter 5 breaks down what the Docker Engine actually is — the part of Docker running in the background, managing containers.

When Docker first launched, it was built around two main components: the Docker Daemon (the brain that exposed the API) and LXC (the backend that actually created the containers). Eventually, Docker ditched LXC and built its own runtime using libcontainer. That gave them more control and flexibility.

From there, Docker evolved into the multi-part engine we have today:

CLI → Docker Daemon → containerd → shim → runc → Container

Here’s how it flows:

  1. Docker CLI – The command-line tool you use when you type something like docker run nginx. It passes your request to the daemon.
  2. Docker Daemon – The API server that receives commands and coordinates the work. It doesn’t manage containers directly anymore; it delegates.
  3. containerd – The lifecycle manager. It pulls images, manages storage, and handles container states like start, stop, and restart.
  4. shim – Keeps the container process alive even if containerd crashes, and also handles input/output streams.
  5. runc – The runtime that talks to the Linux kernel and actually starts the container. It follows the OCI runtime-spec

Once runc creates the container, it hands control back to the shim, which babysits the running process.

The book also mentions OCI, and I think it’s worth stopping here to point that out. OCI — the Open Container Initiative — defines how containers should be built and run. Because of this standard, tools like Docker, Podman, and Kubernetes can all run containers the same way. That’s why containers are portable and consistent — whether you’re running them on Docker Desktop or in a production cluster.

Closing Thoughts

This chapter was a game-changer for me. So many Docker tutorials blur the line between containers and Docker, and that had me tripped up for a while. Taking the time to separate the two made everything click. I hope walking through it this way helps you too, because Chapter 5 is where we really start to understand what’s happening behind the scenes.

That’s it for Chapters 4 and 5. Things are heating up now, and I’m hyped to keep going. As always, stay geeking, stay curious, and I’ll catch you in the next one. Peace!

About the author

Quiet Engineer

A lifelong learner with a passion for tech and soccer. Koroma Tech is where I share my journey and help others along the way. I enjoy taking on challenges and see each one as a chance to learn and grow.

>