Update tech_docs/docker_compose_guide.md
This commit is contained in:
@@ -1,3 +1,150 @@
|
|||||||
|
Learning-GOAL: “I can read, reason about and harden any Dockerfile or `docker run` incantation I meet—without drowning in trivia.”
|
||||||
|
|
||||||
|
Below is a **minimal, language-agnostic curriculum** expressed as executable **pseudocode**.
|
||||||
|
Each block is a self-contained kata you can type, break, fix and extend.
|
||||||
|
```plaintext
|
||||||
|
--------------------------------------------------
|
||||||
|
0. Bootstrapping Sandbox
|
||||||
|
--------------------------------------------------
|
||||||
|
function bootstrap():
|
||||||
|
vm = create_ephemeral_vm() // multipass, lima, or cloud instance
|
||||||
|
install("docker engine") // or podman, nerdctl
|
||||||
|
alias d="docker"
|
||||||
|
return vm
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
1. Core Primitives (must be muscle memory)
|
||||||
|
--------------------------------------------------
|
||||||
|
// 1.1 Image = read-only template
|
||||||
|
function image_primitives():
|
||||||
|
img = build("Dockerfile_hello") // FROM alpine; COPY hello.sh /; CMD ["sh","/hello.sh"]
|
||||||
|
tag = tag(img, "demo:v1")
|
||||||
|
id = inspect(tag, ".Id")
|
||||||
|
layers = history(tag) // list of diff-IDs
|
||||||
|
return {img, tag, id, layers}
|
||||||
|
|
||||||
|
// 1.2 Container = writable runtime instance
|
||||||
|
function container_primitives():
|
||||||
|
c1 = run("-d --name c1 demo:v1")
|
||||||
|
top = exec(c1, "ps aux") // what’s running?
|
||||||
|
delta = diff(c1) // which files changed?
|
||||||
|
commit(c1, "demo:v1-smeared") // bake delta into new image
|
||||||
|
rm(c1)
|
||||||
|
|
||||||
|
// 1.3 Registry = image transport
|
||||||
|
function registry_primitives():
|
||||||
|
reg = start_local_registry() // docker run -d -p 5000:5000 registry:2
|
||||||
|
push("demo:v1", reg)
|
||||||
|
rmi("demo:v1")
|
||||||
|
pull("demo:v1", reg)
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
2. Storage & State (volumes, bind mounts, tmpfs)
|
||||||
|
--------------------------------------------------
|
||||||
|
function storage_primitives():
|
||||||
|
vol = volume_create("db_data")
|
||||||
|
c2 = run("-d -v db_data:/var/lib/postgresql postgres:15")
|
||||||
|
c3 = run("-d --mount src=$(pwd),dst=/src,type=bind alpine sh -c 'sleep 3600'")
|
||||||
|
c4 = run("--tmpfs /tmp:size=100m alpine sh -c 'dd if=/dev/zero of=/tmp/big'")
|
||||||
|
cleanup([c2,c3,c4])
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
3. Networking (CNB model)
|
||||||
|
--------------------------------------------------
|
||||||
|
function networking_primitives():
|
||||||
|
net = network_create("demo_net", driver="bridge")
|
||||||
|
nginx = run("-d --net demo_net --name web nginx")
|
||||||
|
curl = run("--rm --net demo_net alpine/curl curl http://web")
|
||||||
|
assert "Welcome to nginx" in curl.output
|
||||||
|
rm(nginx); network_rm(net)
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
4. Build Secrets & Multi-stage (no plaintext keys)
|
||||||
|
--------------------------------------------------
|
||||||
|
function build_hardening():
|
||||||
|
// Dockerfile.multi
|
||||||
|
// FROM golang:1.22 AS build
|
||||||
|
// RUN --mount=type=secret,id=gh_token \
|
||||||
|
// git config --global http.extraheader "Authorization: Bearer $(cat /run/secrets/gh_token)"
|
||||||
|
// COPY . .
|
||||||
|
// RUN go build -o app .
|
||||||
|
// FROM gcr.io/distroless/static
|
||||||
|
// COPY --from=build /src/app /app
|
||||||
|
// CMD ["/app"]
|
||||||
|
img = build("--secret id=gh_token,env=GH_TOKEN -f Dockerfile.multi .")
|
||||||
|
scan(img) // trivy or grype
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
5. Security Profiles
|
||||||
|
--------------------------------------------------
|
||||||
|
function security_primitives():
|
||||||
|
c5 = run("--cap-drop ALL \
|
||||||
|
--cap-add NET_BIND_SERVICE \
|
||||||
|
--security-opt no-new-privileges:true \
|
||||||
|
--user 1000:1000 \
|
||||||
|
--read-only \
|
||||||
|
--tmpfs /tmp \
|
||||||
|
alpine:latest whoami")
|
||||||
|
assert c5.stdout == "1000"
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
6. Orchestration Lite (Compose as state-machine)
|
||||||
|
--------------------------------------------------
|
||||||
|
function compose_primitives():
|
||||||
|
services = load("compose.yml") // web, redis, db
|
||||||
|
stack = compose_up(services)
|
||||||
|
assert http_get("http://localhost:8080") == 200
|
||||||
|
compose_down(stack)
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
7. Observability & Debug (no black boxes)
|
||||||
|
--------------------------------------------------
|
||||||
|
function observability():
|
||||||
|
c6 = run("-d demo:v1")
|
||||||
|
logs_tail(c6)
|
||||||
|
stats = container_stats(c6) // cpu, mem, blkio
|
||||||
|
enter(c6, "sh") // nsenter for low-level poke
|
||||||
|
rm(c6)
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
8. Cleanup Ritual
|
||||||
|
--------------------------------------------------
|
||||||
|
function cleanup(containers):
|
||||||
|
for c in containers:
|
||||||
|
stop(c, timeout=5)
|
||||||
|
rm(c, volumes=True)
|
||||||
|
system_prune(all=True)
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
9. Mastery Checklist
|
||||||
|
--------------------------------------------------
|
||||||
|
can_i:
|
||||||
|
▢ explain the difference between an image, a layer, and a container
|
||||||
|
▢ build multi-stage with secrets and non-root user
|
||||||
|
▢ launch two containers on a custom bridge and capture traffic
|
||||||
|
▢ run a read-only container that still writes temporary files
|
||||||
|
▢ read `docker inspect` JSON and spot the security-options stanza
|
||||||
|
▢ translate a `docker run` one-liner into compose YAML and back
|
||||||
|
▢ upgrade base image without cache, then surgically bust only the vulnerable layer
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
10. Exit Condition
|
||||||
|
--------------------------------------------------
|
||||||
|
if mastery_checklist.all_true():
|
||||||
|
print("You now own the primitives. Dive into BuildKit, rootless, or Kubernetes.")
|
||||||
|
else:
|
||||||
|
iterate()
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
Usage Notes
|
||||||
|
--------------------------------------------------
|
||||||
|
- Replace every function with real shell commands (`docker build …`, `docker network create …`).
|
||||||
|
- No single file is more than 40 lines; the goal is repetition, not rote memorization.
|
||||||
|
- Re-run the entire pseudocode weekly on a fresh VM to avoid stale muscle memory.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Ah, I see—you’re asking for a **meta-comparison** that aligns with your framing of *"deterministic serendipity"* (predictable yet flexible configurations) and focuses on **functional parallels** between Docker Compose and Talos Linux’s approach, even if their primary use cases differ. Let’s reframe this as:
|
Ah, I see—you’re asking for a **meta-comparison** that aligns with your framing of *"deterministic serendipity"* (predictable yet flexible configurations) and focuses on **functional parallels** between Docker Compose and Talos Linux’s approach, even if their primary use cases differ. Let’s reframe this as:
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user