Architecture overview, design decisions, Docker/networking/OAuth2/Linux concept deep-dives, cert roadmap for cloud engineering track, interview prep with model answers, and structured learning path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.2 KiB
Docker — What It Actually Is
The Wrong Mental Model
Most people think containers are "mini virtual machines." They're not. Understanding the real model is what makes Docker make sense.
What a Container Actually Is
A container is a process (or group of processes) running on the host Linux kernel, with two things applied:
- Namespaces — isolation. The process gets its own view of the filesystem, network, processes, users. It can't see other containers' processes.
- cgroups (control groups) — resource limits. The process is limited to a certain amount of CPU, RAM, etc.
That's it. There's no second kernel. No hypervisor. No hardware emulation. The nginx running in your homepage container is a regular Linux process on your laptop — it just thinks it's alone.
This is why containers start in milliseconds (no boot) and use almost no overhead.
Images vs Containers
| Concept | Analogy | What it is |
|---|---|---|
| Image | A recipe | A read-only template — filesystem layers, default command, environment |
| Container | A meal cooked from that recipe | A running instance of an image — has its own writable layer on top |
You can run 10 containers from the same image. They all share the read-only image layers and each gets their own writable layer on top. If a container is deleted, its writable layer is gone. The image remains.
When you run docker compose up -d, Docker:
- Pulls the image if not already local
- Creates a container (adds writable layer)
- Attaches it to the specified networks
- Mounts the volumes
- Starts the process defined in the image's CMD or your compose override
Docker Networks — Why the kitestacks Network Exists
Docker creates several default networks. Containers on the same network can reach each other by container name (Docker has its own DNS built in).
In this homelab:
docker network create kitestacks
Every container joins this network. So when cloudflared routes traffic for www.kitestacks.com, it resolves homepage via Docker DNS to the container's IP on the kitestacks network. Without this shared network, cloudflared can't find the other containers.
cloudflared container → DNS lookup "homepage" → 172.x.x.x (homepage container)
network_mode: host is different — the container shares the HOST's network namespace entirely. No isolation. Used for the metrics API so it can read actual host network stats.
Volumes — Keeping Data When Containers Are Deleted
Containers are ephemeral — their writable layer is deleted when the container is removed. To persist data:
Bind mount: Links a host directory to a container path.
volumes:
- ./data:/forgejo-data
./data on your laptop → /forgejo-data inside container. Data lives on your laptop. You can browse it with ls.
Named volume: Docker manages the storage location.
volumes:
- prometheus-data:/prometheus
Docker stores it in /var/lib/docker/volumes/prometheus-data/. You don't specify where.
In this homelab: Databases, config files, and user data use bind mounts (./data, ./config, etc.) so you know exactly where everything is. Named volumes are used where location doesn't matter (Prometheus metrics, Portainer settings).
Docker Compose — What It's Doing
docker compose up -d reads docker-compose.yml and for each service:
- Ensures the image exists (pull if needed)
- Creates the network if it doesn't exist
- Creates the container with all specified config (env vars, volumes, ports, networks)
- Starts the container
-d means detached — run in background.
restart: unless-stopped means Docker will restart the container if it crashes or if the host reboots — unless you explicitly stop it with docker compose stop.
Port Mappings
ports:
- "3006:3000"
HOST_PORT:CONTAINER_PORT
Port 3000 inside the container is mapped to port 3006 on the host. From the host, http://localhost:3006 reaches the service. From within the kitestacks Docker network, other containers use http://forgejo:3000 (the container port, via Docker DNS).
Cloudflare Tunnel doesn't use host ports — it goes through the Docker network directly using the container name and container port.
Commands to Know Cold
# See all running containers
docker ps
# See logs for a container
docker logs forgejo
docker logs -f forgejo # follow (live tail)
# Execute a command inside a running container
docker exec -it forgejo bash # open a shell
docker exec forgejo forgejo admin user list # run a specific command
# Inspect a container's config
docker inspect authentik
# See all networks
docker network ls
docker network inspect kitestacks
# See disk usage
docker system df
# Remove unused images/containers/networks
docker system prune
What to Say About Docker
"I containerized every service using Docker and Docker Compose. Each service is isolated in its own container with its own dependencies, connected through a shared Docker bridge network named 'kitestacks' so they can communicate by container name. Data is persisted via bind-mounted host directories. The entire stack is defined in version-controlled YAML files, making it reproducible on any Linux host."