Lesson 6 · This repo's local dev

The two local stacks

docker-compose vs kind + Skaffold — why this repo has both, and the surprising thing they share.

Your win: know the two ways to run the whole backend locally, when to reach for each, and the non-obvious fact that the compose stack's config is generated from the Skaffold stack.

Two stacks, one backend

You can bring the entire backend up on your laptop in two completely different runtimes:

docker-composekind + Skaffold
Entry point./local/run.bash./deployments/sk.bash
RuntimeDocker Compose (Lesson 4)a real Kubernetes cluster
Clusternone — just containerskind (K8s-in-Docker)
Deploys viadocker compose upSkaffold → Helm → kubectl
Speedfast, lightslower, heavier
Fidelity"just the processes"production-like (namespaces, Services, Istio)
Namespacen/alocal-manabie-backend (Lesson 5)
When to use which Use docker-compose for day-to-day service work — it's the fast inner loop, and it's what you already run. Use kind + Skaffold when you need the parts that only exist in Kubernetes: how a Deployment/Service behaves, Helm rendering, Istio routing, KEDA autoscaling. Interview framing: "compose for speed, kind for fidelity."

Stack 1 — docker-compose (run.bash)

What Part 1 described: infra + service + migration Compose files, a wait-for-it-service healthcheck gate, ~25 services all on local-manabie-network. Bring it all up with a bare ./local/run.bash (local/run.bash:107-170) — it builds the image, generates configs, creates the shared volume/network, and runs compose-up-all.bash.

Stack 2 — kind + Skaffold (sk.bash)

This one spins up an actual Kubernetes cluster inside Docker containers using kind, then uses Skaffold to build the images and deploy the Helm charts into it.

Anchor — how sk.bash boots a cluster A plain ./deployments/sk.bash ends in a skaffold run, and just before it, start_cluster() (deployments/sk.bash:126-129) calls deployments/kind_with_registry.bash — kind plus a local image registry. It deploys with flags --default-repo=asia.gcr.io/student-coach-e1e95 --skip-tests --status-check=false against kube-context kind-kind, namespace local-manabie-backend (deployments/sk.bash:14-15). -d deletes the whole cluster.

The surprise: the stacks aren't really independent

Compose configs are rendered from Skaffold/Helm You might assume the two stacks keep separate config. They don't. When run.bash starts everything, build_config_and_secrets() (local/run.bash:22-35) shells out to the Skaffold stack to produce the compose configs:
./deployments/sk.bash -- render -f skaffold.backend.yaml -p local-docker-compose,-local --output ./local/configs/backend.yaml
So Helm (via Skaffold render, Lesson 7) is the single source of truth for configuration; the compose files just consume its output. Change a Helm value and both stacks see it. This is why the two aren't allowed to drift.
Helm charts + {env}-{org}-values.yaml (single source of config truth) │ skaffold render ┌─────────────────────────────┐ ├───────────►│ Stack 1: docker-compose │ ← run.bash (fast) │ └─────────────────────────────┘ │ ┌─────────────────────────────┐ └───────────►│ Stack 2: kind + Skaffold run │ ← sk.bash (production-like) └─────────────────────────────┘
Read this next

kind — Kubernetes IN Docker

What kind is and how it runs a real cluster inside containers — the foundation of Stack 2 and a running theme in Course 2 (Kubernetes).

kind.sigs.k8s.io
→ In-repo: local/run.bash:22-35 · deployments/sk.bash:126-129

Check yourself (from memory)

Q1. The kind + Skaffold stack differs from compose in that it…

kind = Kubernetes-in-Docker; Skaffold builds + deploys the Helm charts into it. Production-like, at the cost of speed.

Q2. Where do the docker-compose stack's configs come from?

run.bash calls sk.bash -- render; Helm is the single config source, so the stacks can't drift.

Q3. For fast day-to-day service iteration you'd reach for…

Compose is the fast inner loop; save kind for testing K8s/Helm/Istio-specific behaviour.
Two local stacks — name them, when to use each, and what they share.
recall, then click to reveal
STACK 1 — docker-compose via ./local/run.bash: plain containers, FAST, day-to-day service dev. STACK 2 — kind + Skaffold via ./deployments/sk.bash: a REAL Kubernetes cluster (kind = K8s-in-Docker) with Skaffold building + deploying Helm charts into namespace local-manabie-backend — SLOWER but production-like (Services, Istio, KEDA). Rule: "compose for speed, kind for fidelity." SHARED: the compose configs are RENDERED from Helm via skaffold render (run.bash:22-35) — Helm is the single config source, so the two stacks can't drift.
Want to know what kind_with_registry.bash sets up, or why a local registry is needed? Ask me.

1. kind — Kubernetes in Docker; in-repo local/run.bash:22-35,107-170, deployments/sk.bash:14-15,126-129.