# Cheat sheet — Containers & Local Dev

Dense revision sheet. Prints to ~1 page. Interview one-liners at the bottom.

---

## Container vs VM (the answer they want)

| | Container | Virtual Machine |
|---|---|---|
| Isolates via | kernel **namespaces** + **cgroups** | a hypervisor + guest kernel |
| Guest OS | **none** — shares host kernel | full guest OS per VM |
| Startup | ms–seconds | seconds–minutes |
| Size | MBs | GBs |
| Isolation strength | weaker (shared kernel) | stronger (separate kernel) |

**One-liner:** "A container is an isolated *process*, not a *machine* — namespaces give it a
private view of the system, cgroups cap its resources, and it shares the host kernel."

---

## Image ≠ Container
- **Image** = read-only template (stacked layers + metadata). Built once, stored in a registry.
- **Container** = a running instance of an image, with a thin writable layer on top.
- One image → many containers.

## Dockerfile essentials
```dockerfile
FROM debian:12.11            # base image (a layer)
RUN apt-get install -y curl  # each instruction ≈ one layer
COPY ./build/server /server  # copy host files in
ENV KEY=value                # runtime env
ENTRYPOINT ["/server"]       # the process that runs
```
- `docker build -t name:tag .` → image. `docker run name:tag` → container.
- **Layer cache:** an instruction is re-run only if it or something above it changed. So put
  the stuff that changes *least* (deps) **above** the stuff that changes *most* (your code).

## Multi-stage (what `Dockerfile.development` does)
```dockerfile
FROM debian AS curl-ready      # build/tooling stage
RUN ...download tools...
FROM debian AS developer       # runtime stage
COPY --from=curl-ready /bin/x /bin/x   # take only what you need
```
→ fat build tools stay out of the shipped image.

## Run-time surface
| Need | Docker flag | Compose key |
|---|---|---|
| Publish a port | `-p 5432:5432` | `ports:` |
| Persist data | `-v name:/path` | `volumes:` (named) |
| Mount host code | `-v ./src:/app` | `volumes:` (bind) |
| Env var | `-e KEY=val` | `environment:` |
| Pick the network | `--network net` | `networks:` |
| Override the command | `... args` | `command:` |

**Named volume** = Docker-managed, persists (data). **Bind mount** = host path (config/code).

## Docker Compose (one file, many services)
```yaml
services:
  db:
    image: postgres:15
    ports: ["5432:5432"]
    volumes: [postgres_data:/var/lib/postgresql/data]
    healthcheck: { test: ["CMD-SHELL","pg_isready -U postgres"] }
  app:
    image: new-backend:locally
    depends_on:
      db: { condition: service_healthy }   # wait for READY, not just started
    command: [gserver, bob]
volumes: { postgres_data: {} }
networks: { local-manabie-network: {} }
```
- Containers reach each other by **service name** (`db`) on the shared network.
- `docker compose up -d` / `down` / `logs -f` / `ps` / `exec svc sh`.
- Plain `depends_on` ⇒ waits for *start*. `condition: service_healthy` ⇒ waits for *health*.

---

## This repo (anchors)
| Thing | Where |
|---|---|
| The dev image (multi-stage) | `local/Dockerfile.development` |
| The one binary copied in | `Dockerfile.development:50` (`COPY ./build/server /server`) |
| Live reload | `modd` entrypoint + `run.bash` `docker cp` hot-swap (`:161`) |
| Infra containers (db, unleash…) | `local/docker-compose.infra.yaml` |
| ~25 backend services | `local/docker-compose.service.yaml` (`image: new-backend:locally`) |
| The readiness gate | `wait-for-it-service` + `depends_on: service_healthy` |
| Day-to-day command | `local/run.bash start -s <svc>` |
| kind + Skaffold local K8s *(Pt2)* | `deployments/sk.bash` (ctx `kind-kind`, ns `local-manabie-backend`) |
| Skaffold config-of-configs *(Pt2)* | `skaffold.local.yaml` (`requires:` many) |
| env×org values *(Pt2)* | `deployments/helm/backend/<svc>/{env}-{org}-values.yaml` |

---

## Interview one-liners
- **What's a container?** *"An isolated process sharing the host kernel — namespaces for
  isolation, cgroups for limits. Not a VM: no guest OS."*
- **Image vs container?** *"Image = read-only template of stacked layers; container = a running
  instance with a writable top layer. One image, many containers."*
- **Why layer order matters?** *"Layers are cached top-down; a change busts the cache for
  everything below. Put rarely-changing deps above frequently-changing code."*
- **Why multi-stage?** *"Build with the full toolchain, ship only the runtime — smaller,
  safer images."*
- **Named volume vs bind mount?** *"Named = Docker-managed persistent data; bind = a host path
  for config/code you edit."*
- **Compose `depends_on` gotcha?** *"By default it waits for *start*, not *ready*. Use
  `condition: service_healthy` + a healthcheck — like this repo's `wait-for-it-service`."*
- **Two local stacks here?** *"Compose (`run.bash`) for fast service dev; kind+Skaffold
  (`sk.bash`) for production-like K8s/Helm/Istio testing."*
