Docker 컨테이너는 어떻게 실행되나|namespaces와 cgroups
A Docker container is not a virtual machine with its own kernel. It is a set of Linux processes isolated by namespaces and constrained by cgroups, all running on the same host Linux kernel. This article summarizes the mechanics of Docker container execution and how docker run actually works, based on docs.docker.com.
This article is a general overview based on Docker’s official documentation. Details can vary with the engine and runtime version and the host kernel (cgroup v1/v2, and so on).
How is a Docker container different from a VM?
Short answer: A VM boots a guest kernel on top of a hypervisor. A Docker container shares the host Linux kernel directly and is just a set of isolated processes.
A hypervisor-based VM runs a full guest OS on top of virtualized hardware. Each VM has its own kernel, which provides strong isolation but comes with noticeable boot time and memory overhead.
A Docker container has a fundamentally different structure. There is no guest kernel. The host OS kernel is shared directly. Because there is no kernel to boot, a container starts at roughly the same speed as any other process. As the official documentation explains, there is no separate “container” object inside the kernel. A container is simply a collection of processes to which isolation (namespaces) and resource limits (cgroups) have been applied.
- Hypervisor: VMs require a hypervisor and a guest OS. Containers share the host kernel directly.
- Start time: A container starts as quickly as a single process because there is no kernel to boot.
- Kernel view: A container is not a kernel object. It is a process group that namespaces and cgroups have been applied to.
What do namespaces isolate in a container?
Short answer: Namespaces are a kernel feature that controls what a process can see. Each container gets its own view of system resources.
A namespace partitions the set of system resources visible to a process. A process inside a namespace sees only the resources that belong to its own namespace. Docker uses several namespaces to build a container’s isolated environment.
- PID: Creates an independent process ID space. The first process inside a container receives PID 1 and is completely separate from the host PID hierarchy.
- NET: Isolates the full network stack — interfaces, IP addresses, routing tables, and iptables rules — giving each container its own network view.
- MNT: Provides a separate mount-point view, so each container has its own root filesystem.
- UTS: Allows each container to set its own hostname and domain name independently from the host.
- IPC: Isolates inter-process communication resources such as semaphores, message queues, and shared memory.
- USER: Maps the container’s root UID to an unprivileged UID on the host, limiting the blast radius if a process escapes the container.
This isolation concept is an evolution of older Linux tools such as chroot and pivot_root. The idea of an “isolated process with its own root filesystem view” belongs to the same family of techniques.
How do cgroups limit CPU, memory, and I/O in a container?
Short answer: cgroups (Control Groups) is a kernel feature that controls how much a process group can consume. This is separate from the isolation that namespaces provide.
If namespaces control what a process can see, cgroups control how much it can use. The two mechanisms serve different purposes, and confusing them is a common source of misunderstanding. Docker primarily manages the following cgroup resource categories.
- Memory: Caps the maximum memory a container can use. Without a limit, a single container can exhaust host memory and cause OOM (Out of Memory) conditions for the entire system.
- CPU: Sets CPU usage quotas and weights (shares) to distribute CPU time across containers.
- Block I/O: Throttles per-container disk read and write throughput.
- PIDs: Caps the number of processes a container can create, preventing fork-bomb style resource exhaustion attacks.
What is the call path from docker to dockerd to containerd to runc?
Short answer: docker run passes through a layered runtime stack — CLI, dockerd, containerd, and runc — before the kernel-level container actually starts.
Docker’s runtime is split into layers by responsibility. Each layer handles a specific concern.
- CLI (
docker): The user typesdocker run. The CLI sends an API request to the Docker daemon over a Unix socket or TCP. The CLI itself does not start any container. - dockerd (Docker Daemon): Receives the API request and handles high-level concerns such as image pulls, network setup, and volume management. It then delegates the actual container lifecycle to
containerd. - containerd: Prepares the image according to the OCI image specification and manages the container lifecycle (create, start, stop, delete). Low-level execution is delegated to
runc. - runc (OCI runtime): Applies the namespaces, cgroups, and rootfs configuration to the Linux kernel and then
execs the specified process. It is the reference implementation of the OCI Runtime Specification.
What does a process look like on the host immediately after docker run?
Short answer: Inside the container the process appears as PID 1. On the host, ps -ef shows the same process as an ordinary PID in the host process tree.
When a container starts, runc uses the MNT namespace to set up a filesystem view consisting of the image’s read-only layers topped by a container-specific writable layer. The detailed structure of those layers (overlay2, and so on) is covered in part 3 of this series.
Thanks to the PID namespace, the process inside the container sees itself as PID 1. On the host, however, ps -ef or ls /proc shows the same process with an ordinary host PID. This difference in perspective illustrates the core idea: from the kernel’s point of view, a container is just a process with a specially constructed view.
FAQ
Short answer: Containers share the kernel and are isolated through namespaces and cgroups. PID namespace behavior and cgroup configuration drive most of the common questions.
| Question | Answer |
|---|---|
| What does PID 1 mean inside a container? | The PID namespace gives each container its own PID space, so the first process the container starts (the specified command) receives PID 1. When that process exits, the container stops. |
What does --pid=host do? | It shares the host’s PID namespace with the container. Processes inside can see the host’s full process tree, and PID isolation is removed. Use with care depending on security requirements. |
| What is the difference between cgroup v1 and v2? | cgroup v1 uses separate hierarchies for each resource type. cgroup v2, introduced in kernel 4.5, uses a single unified hierarchy and is now the default on many modern Linux distributions. Docker detects and uses whichever version the host kernel supports. |
| Is a container fully isolated from the host? | Not fully. Beyond namespaces and cgroups, Docker applies capabilities and seccomp filtering, but containers share the host kernel. A kernel vulnerability is shared across all containers on the host. This trade-off should be evaluated for security-sensitive workloads. |
References
Short answer: Facts in this article are drawn from Docker’s official documentation checked on 2026-09-14.
- What is a container? — Docker Docs — Used to check the container vs. VM comparison, the namespace concept, and the isolation model.
- Run containers — Docker Docs — Used to check
docker runbehavior, the runtime stack, and the container lifecycle. - Docker Engine overview — Docker Docs — Used to check the role separation of dockerd, containerd, and runc.