Files
soleprint/rig/README.md
2026-09-22 05:15:49 -03:00

8.2 KiB

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:

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.

cp -r /mnt/c/Users/<you>/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

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/, one file per script, so the code keeps short comments.

Then

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:

make check                  # ... registry    localhost:<port>  (running)
docker build -t localhost:<port>/app:1 .
docker push localhost:<port>/app:1
kubectl --context kind-$(basename $PWD) run app --image=localhost:<port>/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:

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.

On a machine where Docker really is the only thing installed, make deps has nothing to download with — see 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.

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 <project>/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
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/<name>.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 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:

OVERLAY=examples/data make cluster up