🐳 Docker Does Not Create Containers - Wait, What?!
During the past few months, I've been conducting technical interviews for DevOps/SRE roles in my team. It's been fascinating and insightful to talk to various people - from fresh graduates to experienced engineers - who regularly use containerization tools.
However, one thing struck me repeatedly during these conversations:
Many people believe Docker itself creates containers, and that without Docker, containers cannot exist.
Many candidates expressed surprise when I told them: "Docker itself doesn't actually create containers." They often responded with disbelief: "Wait, how? Isn't Docker all about containers? Isn't Docker responsible for creating containers? How else would you create containers if Docker doesn't do it?"
This got me thinking - I should write a detailed blog to clarify this common misconception and share some insights into what actually creates containers. So today, let’s dive deep into the world of containers, Docker, container runtimes, and see a practical example with a simple yet powerful "ContainerHub" project I created for managing container lifecycles.
🚩 The Docker Misconception: Clearing the Air
First things first - let's address the elephant in the room:
Docker is not directly responsible for creating containers.
This might seem confusing, given Docker’s immense popularity in the containerization ecosystem. Docker made container technology accessible and developer-friendly, leading to widespread adoption. But under the hood, Docker itself relies on specialized components known as container runtimes to actually create and manage containers.
To put it clearly:
Docker is a user-friendly tool providing an intuitive interface and a set of commands that help you build, manage images, and interact with containers.
Container runtime (like containerd and runc) is the one actually creating and running containers at the OS/kernel level.
Confused? Let's break down these concepts further.
🎯 What Exactly is Creating Containers, then?
Behind Docker lies a core component called a container runtime, responsible for container lifecycle management.
Creating containers involves packaging an application and its dependencies into a standardized unit that can be run consistently across different environments. Containers fundamentally rely on two types of runtimes:
High-Level Container Runtime
High-level container runtimes manage the overall lifecycle of containers, including image creation, transport, and orchestration. Here are their key functions:
Image Management: High-level runtimes handle the creation, storage, and distribution of container images. They allow developers to build images from Dockerfiles or other configuration files.
Transport: They manage the transport of container images from registries to the host system where containers will be run.
API Access: High-level runtimes provide APIs for interacting with containers, enabling operations like starting, stopping, and monitoring containers.
Networking: They set up networking between containers, allowing them to communicate with each other and the outside world.
Volume Management: High-level runtimes prepare and manage volumes that containers use for persistent storage.
Delegation: They delegate the actual running of containers to low-level runtimes.
Low-Level Container Runtime
Low-level container runtimes focus on the technical aspects of running containers. Their main responsibilities include:
Namespace Setup: They set up Linux namespaces to isolate system resources like the file system, network, and process IDs for each container.
Cgroups Management: Low-level runtimes manage cgroups to limit and allocate resources such as CPU and memory to containers.
Command Execution: They run commands inside the namespaces and cgroups, ensuring the container operates within its isolated environment.
Filesystem Setup: Low-level runtimes set up the root filesystem for containers, often using chroot to change the root directory.
Resource Limits: They enforce resource limits on containers, ensuring they do not exceed allocated CPU, memory, and other resources.
🔧 Why the Misunderstanding?
Docker's simplicity is the main reason for this confusion. When developers use Docker, everything seems seamless. You type `docker run`
, and the container magically appears.
But behind the scenes, Docker delegates this task to runtimes like containerd and runc.
Docker → calls → containerd → calls → runc → Linux kernel → creates containers
💡 Practical Illustration: Introducing ContainerHub
To illustrate how containers can be managed independently of Docker, I've developed ContainerHub, a practical, lightweight project that directly interacts with container runtimes.
🚀 How Does ContainerHub Work (Without Docker!)
ContainerHub manages container lifecycles directly, demonstrating a clear separation of concerns:
Root Filesystem Preparation: Unlike Docker, ContainerHub requires manual preparation of a root filesystem since no high-level runtime is involved.
Daemon (
containerhubd
): A gRPC server that manages container states and interacts directly with runc.Client CLI (
containerhub
): Communicates through sockets to the daemon, allowing direct management of containers.Storage: Container states and OCI-compliant configurations are stored systematically at
/var/lib/containerhub/<id>
.
This setup clearly shows the fundamental responsibilities of container runtimes independently of Docker.
✅ Benefits of Understanding this Clearly
Knowing that Docker itself doesn’t create containers directly brings several benefits:
Enhanced Debugging: Easier to troubleshoot issues by directly interacting with container runtimes.
Flexibility: You're free to use alternative container runtimes like Podman, containerd, or CRI-O.
Better Architecture Decisions: Helps you make informed decisions around security, resource management, and rootless containers.
🎖️ Conclusion and Takeaways
I hope this blog clears up the confusion:
Docker is a powerful tool, but containers are actually created and managed by underlying runtimes like containerd and runc.
Using the ContainerHub example, I've practically demonstrated this concept clearly. Next time someone says "Docker creates containers," you can confidently explain the reality:
“Docker doesn’t create containers itself - it relies on OCI-compliant container runtimes like containerd and runc to do that!”
I'd love to hear your thoughts, experiences, or questions in the comments below!
Happy Containerizing! 🚀🚀🚀