kitestacks-homelab/homelab-mastery/concepts/docker.md
kenpat 0d3fc4051c merge: add homelab-mastery as subdir
Moved homelab-mastery repo content into homelab-mastery/ subdirectory.
Covers architecture, concepts, certifications, interview-prep, and learning-path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 00:33:54 -05:00

126 lines
5.2 KiB
Markdown

# 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:
1. **Namespaces** — isolation. The process gets its own view of the filesystem, network, processes, users. It can't see other containers' processes.
2. **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:
1. Pulls the image if not already local
2. Creates a container (adds writable layer)
3. Attaches it to the specified networks
4. Mounts the volumes
5. 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.
```yaml
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.
```yaml
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:
1. Ensures the image exists (pull if needed)
2. Creates the network if it doesn't exist
3. Creates the container with all specified config (env vars, volumes, ports, networks)
4. 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
```yaml
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
```bash
# 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."*