| |

Docker 1 ๐Ÿณ Containerization Fundamentals: Containers vs Virtual Machines (VMs)

Containerization is the practice of packaging an application together with all its dependencies โ€” libraries, runtime, system tools, and configuration โ€” into a single, portable unit that can run consistently across any environment. Docker, released in 2013, did not invent this concept, but it standardized the tooling and workflow in a way that made containers practical for everyday developers . The core insight behind Docker is simple: rather than shipping your application alone and hoping the target machine has the right dependencies, you ship the application and its entire user-space environment as one immutable artifact.

The distinction between containers and virtual machines is the foundation on which everything else in Docker rests. Both provide isolation and portability, but they achieve these goals through fundamentally different mechanisms. A virtual machine simulates an entire computer, including its own operating system kernel. A container, by contrast, uses the host’s kernel and isolates only the application layer. This architectural difference produces dramatic consequences for resource usage, startup time, security boundaries, and operational complexity.

This chapter covers the architectural foundations of containers, how they differ from virtual machines at the kernel level, the Linux primitives that make containerization possible, and the practical trade-offs between the two approaches. We will examine namespaces, cgroups, and the layered image model that together form the technical basis of Docker.

Key point: Containers share the host operating system’s kernel and isolate only the application layer, while virtual machines run a complete guest operating system with its own kernel. This makes containers lightweight and fast but gives VMs stronger isolation boundaries.


Why containers exist alongside virtual machines

The reproducibility problem. Software that works on a developer’s laptop often fails in testing or production because the environments differ โ€” different library versions, different system configurations, different operating system patches. Virtual machines solved this by shipping an entire operating system, but at a cost: each VM carries gigabytes of OS files and consumes dedicated CPU and memory even when idle. Containers address the same problem by packaging only the application and its user-space dependencies, sharing the host kernel and its resource pool . The result is a unit of deployment that is both reproducible and economical.

The resource density problem. A typical virtual machine requires pre-allocated CPU, memory, and storage, much of which sits idle. Running twenty VMs on a server means twenty complete operating systems, each consuming memory for kernel structures, device drivers, and background services. Containers eliminate this duplication by sharing a single kernel. Each container adds only the memory footprint of its application processes and the filesystem layers it needs. This allows an order of magnitude more workloads to run on the same hardware .

The startup latency problem. Booting a virtual machine involves loading a kernel, initializing device drivers, starting system services, and reaching a usable state โ€” a process measured in tens of seconds to minutes. Starting a container involves creating a process with a new set of namespaces and a filesystem view, a process measured in milliseconds . This speed difference changes the economics of scaling: containers can be started and stopped rapidly in response to load, while VMs must be provisioned ahead of time.

The packaging and distribution problem. Virtual machine images are large โ€” often tens of gigabytes โ€” and are stored in proprietary formats that vary by hypervisor. Docker images are built from layers, each layer representing a filesystem change. Because layers are shared between images, pulling a new image often downloads only the changed layers. The public Docker Hub registry provides a vast ecosystem of pre-built images that developers can pull and run immediately .

The security trade-off problem. Containers provide weaker isolation than virtual machines because they share the host kernel. A kernel vulnerability can potentially be exploited to escape a container and access the host or other containers. Virtual machines, with their separate kernels, present a stronger security boundary. This trade-off is deliberate: containers choose efficiency and speed over the strongest possible isolation, and technologies like user namespaces and seccomp profiles mitigate the risk .


a. The architectural difference: shared kernel vs guest kernel

The fundamental architectural distinction between containers and virtual machines lies in how they interact with the operating system kernel. A virtual machine runs its own kernel. The hypervisor โ€” software like VMware ESXi, Microsoft Hyper-V, or KVM โ€” emulates hardware devices and provides a platform on which a complete operating system can boot. That guest OS manages its own memory, schedules its own processes, and runs its own device drivers. The host OS and the guest OS are independent; they share only the physical hardware .

A container does not have its own kernel. It runs as a set of processes on the host operating system, isolated from other processes through kernel features. The container’s filesystem is constructed from image layers, but the kernel that executes its code is the host’s kernel. This means a container cannot run a different operating system kernel than its host โ€” a Linux container requires a Linux host, and a Windows container requires a Windows host (or a Linux host running a Windows VM) .

This difference has cascading consequences. Because the container shares the kernel, it cannot load kernel modules, cannot have its own device drivers, and cannot run a different kernel version than the host. But in exchange, it avoids the overhead of duplicating the kernel and its associated data structures in memory. The kernel’s page cache, network stack, and scheduler are shared among all containers on the host, leading to more efficient resource utilization .

b. Linux namespaces: the isolation mechanism

Containers achieve isolation through Linux namespaces, a kernel feature that partitions global system resources so that processes in different namespaces see different views of the system. A namespace wraps a global resource in an abstraction that makes it appear to the processes within the namespace that they have their own isolated instance of that resource .

Linux provides several types of namespaces, each isolating a different category of system resource. The PID namespace gives processes their own process ID number space: the first process in a new PID namespace has PID 1, just as init does on a normal system, and processes in different PID namespaces cannot see or signal each other . The mount namespace isolates filesystem mount points, allowing a container to have its own root filesystem view . The network namespace isolates network devices, IP addresses, routing tables, and port numbers, so containers can bind to the same port without conflict . The UTS namespace isolates the hostname and domain name . The user namespace isolates user and group IDs, allowing a process to have root privileges inside the namespace while being unprivileged outside it . The IPC namespace isolates inter-process communication resources like message queues and shared memory . The cgroup namespace isolates the cgroup root directory view .

When Docker starts a container, it creates a new set of these namespaces for the container’s processes. The processes inside see only the resources within their namespaces. From the host, the container’s processes are visible and manageable, but from inside, the container appears as a self-contained system .

c. Control groups: resource limits and accounting

Namespaces isolate what processes can see. Control groups, or cgroups, control how much of a resource they can use. A cgroup is a kernel feature that limits, accounts for, and isolates the resource usage โ€” CPU, memory, disk I/O, network bandwidth โ€” of a collection of processes .

Docker places each container into its own cgroup. This ensures that one container cannot monopolize the host’s CPU, exhaust its memory, or saturate its disk bandwidth, starving other containers or the host itself . System administrators can set hard limits: a container might be restricted to 2 CPU cores, 512 MB of memory, and 100 MB/s of disk throughput. These limits are enforced by the kernel, not by cooperation from the container .

Cgroups also provide accounting: the kernel tracks how much CPU time, memory, and I/O each cgroup consumes. This data feeds into monitoring tools and orchestration systems, enabling automatic scaling and resource optimization . The combination of namespaces and cgroups is what makes containers viable: namespaces provide the illusion of isolation, and cgroups ensure that the illusion does not collapse under resource contention.


Complete Example Session

# ============================================
# PART 1: CHECK DOCKER INSTALLATION
# ============================================
# Verify that Docker is available and running.

docker --version
docker info
# ============================================
# PART 2: RUN A SIMPLE CONTAINER
# ============================================
# Pull and run a minimal Linux container.

docker run hello-world
# ============================================
# PART 3: INTERACT WITH A CONTAINER
# ============================================
# Start an interactive shell inside Ubuntu.

docker run -it ubuntu:latest /bin/bash
# ============================================
# PART 4: LIST CONTAINERS AND IMAGES
# ============================================
# See what is running and what is stored locally.

docker ps
docker ps -a
docker images
# ============================================
# PART 5: INSPECT A CONTAINER
# ============================================
# Examine the configuration and state of a container.

docker inspect <container_id>
# ============================================
# PART 6: LIMIT RESOURCES
# ============================================
# Run a container with CPU and memory limits.

docker run --cpus="1.5" --memory="512m" nginx
# ============================================
# PART 7: VIEW NAMESPACES
# ============================================
# On the host, inspect the namespaces of a
# running container process.

ls -l /proc/<pid>/ns/
# ============================================
# PART 8: VIEW CGROUPS
# ============================================
# Examine the cgroup of a running container.

cat /proc/<pid>/cgroup
# ============================================
# PART 9: BUILD A CUSTOM IMAGE
# ============================================
# Create a Dockerfile and build an image.

cat > Dockerfile << 'EOF'
FROM alpine:latest
RUN apk add --no-cache curl
CMD ["curl", "--version"]
EOF

docker build -t my-curl .
docker run my-curl
# ============================================
# PART 10: COMPARE CONTAINER AND VM
# ============================================
# Start a VM (if available) and compare startup
# time and resource usage with a container.

time docker run --rm alpine echo "container"
time vagrant up  # if vagrant and a box are available

These ten parts move from verifying the Docker installation through running, inspecting, and limiting containers, to examining the underlying namespace and cgroup primitives, building a custom image, and comparing container behavior with a virtual machine. Each step reveals a layer of the containerization stack.


Quick Reference

Containers vs Virtual Machines

AspectContainerVirtual Machine
KernelShares host kernelRuns own guest kernel
Operating systemUser-space portion onlyComplete OS including kernel
Startup timeMilliseconds to secondsSeconds to minutes
SizeMegabytesGigabytes
Resource overheadMinimalSignificant
Isolation strengthLightweightStrong hardware-level
DensityHigh (dozens per host)Low (single digits per host)
PortabilityHigh, OCI standardLower, hypervisor-specific

Linux Namespace Types

NamespaceIsolates
PIDProcess IDs
MountFilesystem mount points
NetworkNetwork devices, stacks, ports
UTSHostname and domain name
UserUser and group IDs
IPCInter-process communication
CgroupCgroup root directory
TimeBoot and monotonic clocks

Docker Core Concepts

ConceptDescription
ImageRead-only template with application and dependencies
ContainerRunnable instance of an image
LayerFilesystem change in an image
DockerfileText file with build instructions
RegistryRepository for storing and sharing images
VolumePersistent storage for containers

Best Practices

โœ… Do This:

FROM alpine:3.19                                    # Pin base image version
RUN apk add --no-cache curl                         # Minimize layers, no cache
COPY app /app                                       # Copy application files
CMD ["/app/run.sh"]                                 # Exec form for proper signals

โŒ Don’t Do This:

FROM alpine:latest                                  # โŒ Unpinned base image
RUN apk update && apk add curl                      # โŒ Leaves cache, larger image
ADD http://example.com/file /app/                   # โŒ Remote URL in ADD
CMD /app/run.sh                                     # โŒ Shell form, poor signal handling

Common Pitfalls

PitfallWhy It HappensFix
Container exits immediatelyNo long-running process in CMDEnsure CMD runs a foreground process
Data lost on container removalContainer filesystem is ephemeralUse volumes for persistent data
Port not accessibleContainer network is isolatedPublish ports with -p host:container
Permission denied on volumeHost and container UID mismatchMatch UIDs or use user namespaces
Image too largeUnnecessary files in layersUse multi-stage builds and .dockerignore
OOM killedContainer memory limit exceededIncrease limit or optimize application

Real-World Examples

1. Development Environment

docker run -it --rm -v $(pwd):/workspace -w /workspace node:20 bash

2. Web Server with Volume

docker run -d -p 8080:80 -v ./html:/usr/share/nginx/html nginx

3. Database with Persistent Storage

docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16

4. Resource-Constrained Service

docker run -d --cpus="0.5" --memory="256m" redis:7

5. Multi-Container Application

# docker-compose.yml
services:
  web:
    build: .
    ports: ["8000:8000"]
  db:
    image: postgres:16

6. CI Build Step

docker run --rm -v $(pwd):/src -w /src golang:1.22 go test ./...

7. Kubernetes Pod

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: nginx
    image: nginx:1.25

8. Container with Healthcheck

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

9. Multi-Stage Build

FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o /app

FROM alpine:3.19
COPY --from=builder /app /app
CMD ["/app"]

10. Docker Compose with Environment

services:
  app:
    image: myapp
    environment:
      - DATABASE_URL=postgres://db:5432/mydb

Visual

Container vs Virtual Machine Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CONTAINER ARCHITECTURE          VM ARCHITECTURE             โ”‚
โ”‚                                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚  App A  โ”‚ โ”‚  App B  โ”‚        โ”‚  App A  โ”‚ โ”‚  App B  โ”‚      โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค      โ”‚
โ”‚  โ”‚  Libs   โ”‚ โ”‚  Libs   โ”‚        โ”‚  Libs   โ”‚ โ”‚  Libs   โ”‚      โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค        โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค      โ”‚
โ”‚  โ”‚         โ”‚ โ”‚         โ”‚        โ”‚ Guest   โ”‚ โ”‚ Guest   โ”‚      โ”‚
โ”‚  โ”‚         โ”‚ โ”‚         โ”‚        โ”‚ OS +    โ”‚ โ”‚ OS +    โ”‚      โ”‚
โ”‚  โ”‚         โ”‚ โ”‚         โ”‚        โ”‚ Kernel  โ”‚ โ”‚ Kernel  โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚       โ”‚           โ”‚                  โ”‚           โ”‚           โ”‚
โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜           โ”‚
โ”‚             โ”‚                              โ”‚                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚   HOST KERNEL       โ”‚        โ”‚    HYPERVISOR       โ”‚      โ”‚
โ”‚  โ”‚   (shared)          โ”‚        โ”‚    (VMware, KVM)    โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚             โ”‚                              โ”‚                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚   HOST OS           โ”‚        โ”‚   HOST OS           โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚             โ”‚                              โ”‚                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚   HARDWARE          โ”‚        โ”‚   HARDWARE          โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚                                                              โ”‚
โ”‚  Containers share the host kernel. VMs run a full guest OS   โ”‚
โ”‚  with its own kernel. This is the fundamental difference.    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Namespace Isolation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  LINUX NAMESPACES IN A CONTAINER                             โ”‚
โ”‚                                                              โ”‚
โ”‚  HOST VIEW:                                                  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  PID 1000 (container init, PID 1 inside)               โ”‚  โ”‚
โ”‚  โ”‚  PID 1001 (container process, PID 2 inside)            โ”‚  โ”‚
โ”‚  โ”‚  PID 1002 (container process, PID 3 inside)            โ”‚  โ”‚
โ”‚  โ”‚  PID 500 (host process, not visible inside)            โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  CONTAINER VIEW (PID namespace):                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  PID 1 (container init)                                โ”‚  โ”‚
โ”‚  โ”‚  PID 2                                                 โ”‚  โ”‚
โ”‚  โ”‚  PID 3                                                 โ”‚  โ”‚
โ”‚  โ”‚  (host PID 500 is invisible)                           โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  Each namespace type isolates a different resource view.     โ”‚
โ”‚  Network: container sees its own eth0, IP, ports.            โ”‚
โ”‚  Mount: container sees its own root filesystem.              โ”‚
โ”‚  User: root inside = unprivileged outside.                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Docker Image Layers

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  IMAGE LAYERS ARE READ-ONLY AND SHARED                       โ”‚
โ”‚                                                              โ”‚
โ”‚  Image: myapp:latest                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  Layer 4: COPY app /app            (read-only)         โ”‚  โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
โ”‚  โ”‚  Layer 3: RUN apk add curl         (read-only)         โ”‚  โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
โ”‚  โ”‚  Layer 2: RUN apk update           (read-only)         โ”‚  โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
โ”‚  โ”‚  Layer 1: FROM alpine:3.19         (read-only)         โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  Container adds a thin writable layer on top:                โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  Writable Layer (container-specific changes)           โ”‚  โ”‚
โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
โ”‚  โ”‚  Read-only layers (shared with other containers)       โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  Multiple containers using the same base image share         โ”‚
โ”‚  the read-only layers, saving disk space and memory.         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Namespaces and Cgroups Working Together

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  HOW CONTAINERS COMBINE NAMESPACES AND CGROUPS               โ”‚
โ”‚                                                              โ”‚
โ”‚  NAMESPACES (what the process SEES):                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  PID   โ†’ sees only its own processes                   โ”‚  โ”‚
โ”‚  โ”‚  NET   โ†’ sees only its own network interfaces          โ”‚  โ”‚
โ”‚  โ”‚  MNT   โ†’ sees only its own filesystem tree             โ”‚  โ”‚
โ”‚  โ”‚  USER  โ†’ sees its own user/group IDs                   โ”‚  โ”‚
โ”‚  โ”‚  UTS   โ†’ sees its own hostname                         โ”‚  โ”‚
โ”‚  โ”‚  IPC   โ†’ sees only its own IPC resources               โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  CGROUPS (how much the process can USE):                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  CPU    โ†’ limited to N cores or percentage             โ”‚  โ”‚
โ”‚  โ”‚  Memory โ†’ limited to M megabytes                       โ”‚  โ”‚
โ”‚  โ”‚  I/O    โ†’ limited to disk bandwidth/IOPS               โ”‚  โ”‚
โ”‚  โ”‚  Tasks  โ†’ limited to N processes/threads               โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  Namespaces provide isolation. Cgroups provide containment.  โ”‚
โ”‚  Together they make a container: isolated and bounded.       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Container definitionIsolated process with its own filesystem, network, and resource limits
Key difference from VMContainers share host kernel; VMs run full guest OS
NamespacesKernel feature for isolating resource views
Namespace typesPID, Mount, Network, UTS, User, IPC, Cgroup, Time
CgroupsKernel feature for limiting and accounting resource usage
Container imageRead-only layered filesystem template
Container instanceWritable layer on top of image layers
Startup timeContainers in milliseconds; VMs in seconds to minutes
Isolation strengthVMs stronger; containers lighter
DensityContainers higher; VMs lower

Key takeaways:

  • Containers share the host kernel. A container does not run its own operating system kernel; it isolates processes using kernel namespaces and cgroups. This is the root of every other difference from VMs.
  • Namespaces isolate resource views. PID, network, mount, user, UTS, IPC, cgroup, and time namespaces give each container its own view of system resources.
  • Cgroups limit and account for resource usage. Without cgroups, a single container could starve other containers and the host of CPU, memory, or I/O.
  • Containers are lightweight and fast. No kernel boot, no device initialization, no system service startup โ€” just process creation with new namespaces.
  • Virtual machines provide stronger isolation. A separate kernel means a vulnerability in the guest kernel does not automatically compromise the host.
  • Images are built from layers. Each Dockerfile instruction creates a read-only layer; containers add a thin writable layer on top.
  • The trade-off is efficiency versus isolation. Containers win on density, speed, and portability; VMs win on security boundaries and guest OS compatibility.

Remember: Docker containers and virtual machines solve the same problem โ€” isolating applications and making them portable โ€” but they solve it at different layers of the stack. A virtual machine virtualizes hardware, allowing a complete operating system to run as if it were on its own computer. A container virtualizes the operating system itself, sharing the kernel while isolating the application’s view of the system. This architectural choice makes containers dramatically lighter and faster, at the cost of a weaker security boundary. Understanding namespaces and cgroups is understanding how containers actually work beneath the Docker command line. Every docker run creates a set of namespaces and a cgroup, and every container image is a stack of filesystem layers waiting to be instantiated as an isolated process tree.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!