Skip to content

Containers & Docker

🌱 Seedling — core concepts documented, examples being added.

Why Containers?

Before containers: monolithic apps with heavy dependencies, slow updates, unpredictable environments. Virtualisation solved isolation at the hardware level but was heavyweight.

Containers isolate at the Linux kernel level (namespaces + cgroups) — same kernel, isolated process spaces. Lighter, faster, portable.

The key shift: "works on my machine" → "works anywhere the container runs".

Docker Architecture

Docker CLI  →  Docker Daemon (dockerd)  →  containerd
                      ↓
              Docker Registry (Hub / private)
                      ↓
              Docker Image → Docker Container
Component Role
dockerd Server-side daemon: pulls images, manages containers, networking, logs
Docker CLI Client: sends commands to daemon locally or over network
Dockerfile Build instructions → produces image layers
Docker Image Packaged, layered, immutable application snapshot
Docker Registry Image storage (Docker Hub, Harbor, GHCR)
Docker Container Running instance of an image (a Linux namespace, essentially)

Key Commands

# Images
docker pull nginx:alpine          # pull from registry
docker build -t myapp:1.0 .       # build from Dockerfile
docker rmi myapp:1.0              # remove image

# Containers
docker run -d -p 8080:80 nginx    # run detached, map port
docker exec -it <id> bash         # shell into running container
docker stop <id>                  # graceful stop (SIGTERM)
docker rm <id>                    # remove stopped container

# Inspect
docker logs -f <id>               # follow logs
docker stats                      # live resource usage
docker inspect <id>               # full JSON config

DRY in Docker: Compose

Avoid running containers with long docker run commands repeated in scripts. Use docker-compose.yml as the single source of truth:

# One .env file, referenced everywhere — DRY
services:
  traefik:
    image: traefik:v3.0
    env_file: .env
  nextcloud:
    image: nextcloud:latest
    env_file: .env          # same .env, not duplicated

→ See this pattern in action: Eigenstack — Sovereign Self-Hosted Cloud (Germany)

Isolation Note

Containers are well-isolated from each other, but less isolated from the host than VMs — they share the kernel. This is why docker-socket-proxy matters in production: direct access to /var/run/docker.sock = potential host root escalation.

→ Mitigated in eigenstack via docker-socket-proxy (no direct socket exposure).