KCNA: Containers and Docker
- 6 minsContainers and Docker
A container isn’t a mini-VM; it’s just a standard Linux process wearing a very sophisticated disguise.
chroot - The Foundation
chroot is a process that changes the root directory for a running process and its children, effectively isolating them from the rest of the system.
Two Key Ingredients That Made Docker Possible
1. Linux Namespaces
- Provide a way to isolate processes at the kernel level
- Create completely isolated environments
- Each namespace has its own:
- Process trees
- Network stacks
- Mount points
| Namespace Type | What It Isolates | Key Features |
|---|---|---|
| Network | Networking stack | Own IP addresses, routing tables, firewall rules |
| Mount | File system mount points | Independent mount points visible only within namespace |
| Process (PID) | Process IDs | Isolated process trees |
| User | User and group IDs | Independent user management |
| UTS | Hostname and domain name | Separate system identity |
| IPC | Inter-process communication | Isolated message queues and semaphores |
2. Control Groups (cgroups)
- Allow for resource allocation and isolation. It prevents other containers from hogging all the CPU or RAM and crashing the host.
- Control and limit:
- CPU usage
- Memory consumption
- I/O bandwidth
- Network usage
Docker combines chroot + Linux Namespaces + cgroups to create:
- Completely isolated environments
- Own processes, network, and mounts
- Repeatable deployments (includes all dependencies)
- Same behavior wherever you run
- Decoupled applications from underlying host infrastructure
Docker Desktop Architecture
- Uses a hidden virtual machine or subsystem
- Runs an isolated instance of Docker
- Provides consistent experience across operating systems
Platform Differences
- macOS - Can customize shared resources in preferences
- Windows - Cannot customize shared resources
Containers vs. Virtual Machines (VMs)
The primary difference is the Kernel.
| Feature | Containers | Virtual Machines |
|---|---|---|
| Guest OS | None (Shares Host Kernel) | Full Guest OS (Separate OS instance) |
| Startup Time | Faster | Slower |
| Resources | Lightweight / High Density | Heavy / Lower Density |
| Isolation | Process-level (Namespaces) | Hardware-level (Hypervisor) |
On macOS and Windows, Docker Desktop runs a tiny, hidden Linux VM to provide the kernel needed for these Linux features to work!
Kernel = the core of the operating system. It directly controls the hardware.
Operating System (OS) = the entire system software that includes the kernel
plus all the tools and programs that make the computer usable.
All containers:
- Call into the same kernel memory
- Use the same:
- scheduler
- memory manager
- filesystem drivers
- network stack
- device drivers
Key Advantage: Kernel Sharing
Containers share the host OS kernel, which:
- Avoids duplication of OS resources
- Enables hosting more workloads on same physical server
- Reduces resource overhead compared to virtualization
When we say containers share the kernel, we literally mean every container’s processes execute system calls inside the exact same running kernel code.
Container Images & The Union Filesystem
A image is a ready-to-run software package (the blueprint) containing everything needed to run an application:
- Application code
- Libraries and dependencies
- Runtime environment
- Configuration and default values
-
Self-contained bundle of software
- Layering: Images are built in layers. If you change one line of code, Docker only rebuilds the affected layer.
- Union Filesystem: This technology merges all those layers into a single, cohesive view for the user.
- Immutability: Containers should be stateless and immutable. You don’t patch a running container; you update the image and redeploy.
- Digest vs. Image ID: * Digest: A unique, content-addressable hash from the registry (e.g., Docker Hub).
- Image ID: A local checksum generated by your Docker engine.
Layered Approach
┌─────────────────┐
│ App Layer │ ← Your application
├─────────────────┤
│ Lib Layer │ ← Dependencies & libraries
├─────────────────┤
│ OS Layer │ ← Base operating system
└─────────────────┘
Key Concepts:
- Stack of individual layers (0-byte commands get bundled)
- Union filesystem merges layers into one view
- Efficient storage through layer reuse
The Image is the blueprint, while a Container is the running instance.
Tags and Versioning
- Tags are labels used to distinguish versions of container images
- Examples:
nginx:latest,nginx:1.21,nginx:alpine - Enable version management and deployment strategies
OCI Compliance
- Images follow Open Container Initiative (OCI) standards
- Not just Docker - works with other container runtimes
- Ensures interoperability across platforms
Persistent Data: Docker Volumes
By default, data inside a container is ephemeral (it dies when the container dies). To keep data safe, we use Volumes.
- Volumes: Managed by Docker. Best for production data, databases, and high-performance I/O.
- Bind Mounts: Maps a specific path on your host machine to the container. Great for local development (changes in your IDE show up instantly).
Optimization: Multi-stage Builds
To keep images small and secure, use multi-stage builds. This allows you to use one large image to compile your code (with all the bulky tools) and then copy only the final executable into a tiny “production” image (like alpine or scratch).
# Build stage
FROM golang:1.19 AS builder
COPY . /app
RUN go build -o myapp
# Final stage
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/
CMD ["myapp"]
Result: Smaller final images, only necessary dependencies and faster deployments.
Golden Rules:
- Stateless Design
- Containers should not store state
- Use external storage for data
- Immutable Containers
- Never change code in running containers
- Rebuild and redeploy instead of modifying
- Everything in the Image
- Include all dependencies
- Ensure consistent behavior across environments
Basic Container Operations
# Start a new container
docker run [OPTIONS] IMAGE_NAME
# Common flags
docker run -it ubuntu:latest # Interactive terminal
docker run -d nginx # Run in background (detached)
docker run -P nginx # Expose all ports
🎛️ Important Docker Flags
| Flag | Purpose | Usage |
|---|---|---|
-i | Interactive | Allows user interaction with container process |
-t | Terminal | Creates terminal I/O environment |
-d | Detached | Runs container in background |
-P | Publish all | Expose all container ports |
-p | Publish specific | Map specific ports (e.g., -p 8080:80) |