# rig A runnable local model of a large, regulated estate — legacy and new side by side. Its job is onboarding and exploration, not a production replica: most services are deliberately mocked, because what has to be faithful is the topology, not the workloads. ## Prerequisite **Docker.** Nothing else — no curl, no jq, no python, no apt repositories. ### Starting from plain Windows Everything here is bash and runs *inside* a Linux shell, so on a Windows machine that means WSL. Nothing in rig installs WSL, and nothing will: `wsl --install` enables Windows features and requires a reboot, which is not something a script should do to a machine on your behalf — and there is no tested undo for it. From an elevated PowerShell or Command Prompt, once: ```powershell wsl --install ``` Then reboot and open the Linux shell it installed. **If you cloned this on the Windows side, copy it into WSL before carrying on.** WSL can reach the Windows drives at `/mnt/c`, and working from there mostly functions — slowly — but file watching does not: that filesystem raises no inotify events, so anything watching for edits silently stops seeing them. ```bash cp -r /mnt/c/Users//rig ~/rig cd ~/rig ``` `make deps` reports it if you are running from `/mnt/...`. Then carry on below. If it fails, the usual causes give unhelpful messages: | symptom | cause | | --- | --- | | "the virtual machine could not be started" | virtualization disabled in BIOS/UEFI | | the command is not recognised | Windows build too old — needs 2004 or later | | the install starts, then nothing works | a reboot is still pending | Running the scripts from **Git Bash, MSYS or Cygwin does not work** — those look close enough to a Linux shell to get started and then fail without `/proc` or a docker socket. `ctrl/deps.sh` detects that and says so rather than letting you find out the slow way. ## Read the docs first ```bash make docs # serves on localhost, prints the URL ``` They run before anything is installed, which matters because they are the instructions for everything else. No cluster and no toolchain required. Why the code is the way it is — the reasoning, measurements and gotchas — lives in [`docs/notes/`](docs/notes/), one file per script, so the code keeps short comments. ## Then ```bash make check # is this machine ready? short; `make check all` for every detail make deps # install the toolchain (add `core` on a managed machine) make cluster up # cluster + registry + the profile's addons ``` That is the whole setup. `make cluster up` also starts this environment's local registry and wires it into the node, so an image built locally is pullable by the cluster without going near docker.io. `make check` shows its port, among everything else: ```bash make check # ... registry localhost: (running) docker build -t localhost:/app:1 . docker push localhost:/app:1 kubectl --context kind-$(basename $PWD) run app --image=localhost:/app:1 ``` The port block is derived from the directory name, so two copies of rig never collide — nothing to configure. `make check all` lists it; `bash ctrl/ports.sh persist` pins it into `ctrl/.env` if you want it fixed: ```bash make cluster list # every cluster on this machine, with memory make cluster free # stop the others if memory is tight make cluster down # remove this cluster and its registry ``` **The verbs are yours to change.** `cluster` is the script — `ctrl/cluster.sh` — and every spelling above is a `Makefile` target that calls it. `make kind-up` is an alias for `make cluster up`, kept because the other projects on this machine answer to that spelling and muscle memory spans repos rather than stopping at one. Nothing outside the `Makefile` reads these names, so rename them, drop the ones you never type, or add whatever your own projects already say: each alias is two lines at the bottom of the file, calling the same script the canonical target does. **`make tilt` works on a fresh copy, unedited.** rig's `ctrl/Tiltfile` does rig's part — identity, context guard, registry, the manifests — and then includes the overlay's own Tiltfile. With no overlay named that is `examples/starter`, so the dev loop comes up with its two examples running and nothing to configure. It hardcodes nothing. It asks `ctrl/ports.sh active` for this environment's cluster name, kube context, ports and paths — the same values every other rig script resolves through `ctrl/lib/config.sh` — so a copied and renamed rig, or a moved overlay, deploys into its own cluster with no edits. `make help` lists every target. `make selftest` checks rig itself, the installer's detection included; `make selftest install` runs the installer on clean containers ([`docs/notes/installer-testing.md`](docs/notes/installer-testing.md)). On a machine where Docker really is the only thing installed, `make deps` has nothing to download with — see [BOOTSTRAP.md](BOOTSTRAP.md), which runs the toolchain through the installer container and carries on to scaffolding and running a new project. ## What runs is an overlay rig is the machine: toolchain, cluster, registry, port block, the dev loop's plumbing. What runs on it is an **overlay** — one folder, outside rig's version control, holding a use case: its settings (`rig.env`), its manifests (`k8s/overlays/dev`), its images and Tiltfile, its addons, its kind config if it needs its own. rig reads it and never writes into it. See [`docs/notes/overlay.md`](docs/notes/overlay.md). ```bash cp -r examples/starter local/myenv # local/ is gitignored OVERLAY=local/myenv make cluster up # or OVERLAY=local/myenv in ctrl/.env OVERLAY=local/myenv make tilt ``` An overlay can also be a repo of its own, anywhere, or a project folder that carries rig at `/rig/` with a three-line forwarding Makefile. ## One environment per folder Cluster name, kubectl context, image tags and the host port block all derive from a folder name — the overlay's when one is named, else rig's own — so copies never collide and neither one's teardown can touch the other. Two overlays run side by side from one rig; two copies of rig do too. ## Profiles **rig needs no profile.** With none named it runs on built-in defaults: one node, no addons, a local registry, the newest Kubernetes version it pins. A profile is an optional file in `ctrl/env.d/`, named by `PROFILE`, that says how this machine reaches the world. rig ships two as **examples**; copy one to use it (the copy is gitignored): | example | what it changes | | --- | --- | | `mirror.env.example` | images through a pull-through cache of an internal registry | | `offline.env.example` | air-gapped: everything from a preloaded local registry | ```bash cp ctrl/env.d/mirror.env.example ctrl/env.d/mirror.env PROFILE=mirror make cluster up ``` The layers, weakest first: built-in defaults < `ctrl/versions.env` < the profile < the overlay's `rig.env` < `ctrl/.env` < your command line. The **cluster itself** is one file: the overlay's `kind-config.yaml.tpl` if it has one, else rig's `ctrl/k8s/kind-config.yaml.tpl` (one node). To change it — more nodes, other port mappings, mounts — edit it and `make cluster reset`. The node count is read back out of it, so there is nothing to drift. ## Addons Each addon is its own idempotent script, and `ADDONS` names the ones to install, in order. Adding one is adding a file — there is no dispatcher to edit. An overlay's `addons/.sh` is found before rig's own. **There is no ingress controller, deliberately.** They pin a narrow window of Kubernetes versions, so depending on one would constrain which k8s a rig can be built with — and running a trailing-edge control plane is often the point. Services are reached through MetalLB and `type: LoadBalancer`, which carries no such constraint and is also what a real cluster does. rig's own addons make the cluster work: | Addon | Does | | --- | --- | | `metallb` | gives `type: LoadBalancer` an address it can actually reach | | `cert-manager` | a local CA, so TLS works offline | | `metrics-server` | makes `kubectl top` work on kind | What a workload needs — a database, a cache, a scheduler — belongs to its overlay. [`examples/data`](examples/data/) carries postgres, redis and airflow as plain manifests (no helm: a chart repo is a network dependency), with passwords generated on first install and kept across re-runs: ```bash OVERLAY=examples/data make cluster up ```