clean rig

This commit is contained in:
2026-09-17 01:12:15 -03:00
parent de5b1b7ea8
commit 1dc9d38c80
12 changed files with 98 additions and 312 deletions

View File

@@ -57,8 +57,7 @@ compose, the same dependency installs as a rig addon of that name:
```bash
cd rig
PROFILE=data make cluster up
PROFILE=data make addons install
PROFILE=data make cluster up # installs the addons too
kubectl -n data port-forward svc/postgres 5432:5432
kubectl -n data port-forward svc/airflow 8080:8080

View File

@@ -97,7 +97,7 @@ build has a Makefile target today. **On a genuinely bare machine, run it by
hand:**
```bash
make deps-image # builds rig-deps:deps
make deps image # builds rig-deps:deps
mkdir -p ~/.local/bin
docker run --rm \
-v /:/host:ro \
@@ -141,7 +141,7 @@ If something else on this machine already provides `kubectl`, the installer says
by name rather than shadowing it quietly. `OUT_BIN=$PWD/def/bin` installs
somewhere private instead.
**Two variants worth knowing before you need them.** `make deps-image full` bakes
**Two variants worth knowing before you need them.** `make deps image full` bakes
every pinned binary into the image at build time (`DEPS_SOURCE=baked`), so
`docker save` gives you the entire installer as one file to carry into an
air-gapped network. And `DEPS_SOURCE=artifactory` with `DEPS_ARTIFACTORY_URL`
@@ -156,16 +156,14 @@ the first-time path.
## Prove the machine before blaming the project
```bash
make setup
make check
make cluster up
kubectl get nodes
```
`make setup` re-runs every check as a group. It is idempotent and it deliberately
does not abort on the first failure — a setup script that dies at step two hides
the fact that steps four and five were also going to fail. Run now, it should be
`ok` and `done` all the way down, and that is the point: it is the scoreboard,
not the installer.
`make check` re-runs every check — host, docker, toolchain, memory, ports — and
changes nothing. Run now, it should end with nothing left to do by hand, and that
is the point: it is the scoreboard, not the installer.
`make cluster up` builds rig's built-in defaults — one node, no addons,
boots fast. You do not need it to develop anything, but you do want to know that

View File

@@ -1,16 +1,18 @@
# Thin control Makefile — one target per ctrl/ script, and the subcommand is an
# argument rather than a second target: `make cluster down`, not `make cluster-down`.
# Thin control Makefile — few targets, and the subcommand is an argument rather
# than a second target: `make cluster down`, not `make cluster-down`.
#
# The logic lives in the scripts, never here. Each target maps to exactly one
# bash file, and that file holds the variants:
# make check is this machine ready? (never changes anything)
# make deps install the toolchain
# make cluster up cluster + registry + addons (ports derive by themselves)
# make tilt / docs work on it, read about it
#
# make cluster up -> ctrl/cluster.sh up
# The logic lives in the scripts, never here: `make cluster up` -> ctrl/cluster.sh up.
#
# Config layers, weakest first: built-in defaults < ctrl/versions.env (pinned
# toolchain) < ctrl/env.d/<profile>.env (optional) < ctrl/.env (local,
# gitignored) < the environment. So `make cluster up PROFILE=<name>` beats them all.
#
# Start with: make setup (then: make cluster up && make docs)
# Start with: make check && make deps && make cluster up
# Identity follows the FOLDER NAME, so this directory can be copied elsewhere,
# renamed, and run as a separate environment with no edits. ctrl/.env overrides
@@ -24,7 +26,7 @@
#
# This used to be sed over ctrl/.env plus a slug computed here, which is a
# SECOND derivation of values lib/config.sh already owns — and the two could
# disagree about the port after `make ports persist`, or about the name for any
# disagree about the port after `ports.sh persist`, or about the name for any
# directory whose sanitised form differs from its raw one. One source now; the
# Tiltfile reads the same line.
FACTS := $(shell bash ctrl/ports.sh active 2>/dev/null)
@@ -50,59 +52,39 @@ $(eval $(ARGS):;@:)
.PHONY: $(ARGS)
endif
.PHONY: help setup check selftest mem deps deps-image standalone cluster registry addons ports \
docs tilt \
.PHONY: help check deps cluster tilt docs selftest standalone \
kind-up kind-down kind-reset tilt-up tilt-down
help: ## list targets
@grep -hE '^[a-z][a-z-]*:.*?##' $(MAKEFILE_LIST) | sed 's/:.*##/\t/' | expand -t16
# ── setup ──────────────────────────────────────────────────────────────────
# ── this machine ───────────────────────────────────────────────────────────
setup: ## prepare this machine [core] [--cluster]
bash ctrl/setup.sh $(ARGS)
# Everything that looks and never changes anything: host, docker, toolchain,
# config, memory, ports, registry, addons. `check mem` goes deeper on memory —
# how far it really climbs, and the WSL .wslconfig backup/restore.
check: ## is this machine ready? [mem [status|push|all|backup|restore]]
bash ctrl/check.sh $(ARGS)
check: ## is this machine ready? reports, never fixes
bash ctrl/check.sh
# The counterpart to check: that one asks about the MACHINE and never fails,
# this one asks about RIG and exits 1, as `make standalone check` does. Checks are written
# as the decisions they defend, so a failure names what is being undone.
selftest: ## does rig still do what it says? exits 1 if not
bash ctrl/selftest.sh
mem: ## memory, its caps, what it survives [status|push|all|backup|restore]
bash ctrl/mem.sh $(or $(ARGS),status)
deps: ## install the toolchain [core|dev] (default dev)
bash ctrl/deps.sh install $(or $(ARGS),dev)
# The one-file versions of rig's tools, one folder per profile, for machines the
# full rig is not going to. Generated from rig as it is, never edited by hand;
# `check` is what selftest runs to catch a kit left behind by a change to rig.
standalone: ## single-file kits [write|check|export DIR] (default write)
bash ctrl/standalone.sh $(or $(ARGS),write)
deps-image: ## build the installer image [full]
# `deps image` is for a machine with nothing but Docker: the installer runs from
# the image instead — see BOOTSTRAP.md. `full` bakes every binary in.
deps: ## install the toolchain [core|dev] [image [full]]
ifeq ($(word 1,$(ARGS)),image)
docker build -f ctrl/Dockerfile.deps \
--target $(if $(filter full,$(ARGS)),deps-full,deps) \
-t $(DEPSIMG):$(if $(filter full,$(ARGS)),full,deps) .
else
bash ctrl/deps.sh install $(or $(ARGS),dev)
endif
# ── cluster ────────────────────────────────────────────────────────────────
# ── the cluster ────────────────────────────────────────────────────────────
# up also starts the registry and installs the profile's addons, and the ports
# derive from the folder name — there is nothing else to run first.
cluster: ## this env + the machine [up|down|reset|list|free]
bash ctrl/cluster.sh $(or $(ARGS),up)
registry: ## registry wiring [up|down|status] (default status)
bash ctrl/registry.sh $(or $(ARGS),status)
addons: ## profile addons [install|list] (default list)
bash ctrl/addons.sh $(or $(ARGS),list)
ports: ## this environment's port block [show|persist]
bash ctrl/ports.sh $(or $(ARGS),show)
# ── docs + dev loop ────────────────────────────────────────────────────────
# ── dev loop + docs ────────────────────────────────────────────────────────
docs: ## documentation [serve|graphs] (default serve)
bash ctrl/docs.sh $(or $(ARGS),serve)
@@ -120,6 +102,20 @@ docs: ## documentation [serve|graphs] (default
tilt: ## dev loop [up|down] (default up)
cd ctrl && tilt $(or $(ARGS),up) $(KCTX) $(if $(filter down,$(ARGS)),,$(if $(TILT_PORT),--port $(TILT_PORT)))
# ── maintaining rig ────────────────────────────────────────────────────────
# The counterpart to check: that one asks about the MACHINE and never fails,
# this one asks about RIG and exits 1. Checks are written as the decisions they
# defend, so a failure names what is being undone.
selftest: ## does rig still do what it says? exits 1 if not
bash ctrl/selftest.sh
# The one-file versions of rig's tools, one folder per profile, for machines the
# full rig is not going to. Generated from rig as it is, never edited by hand;
# `check` is what selftest runs to catch a kit left behind by a change to rig.
standalone: ## single-file kits [write|check|export DIR] (default write)
bash ctrl/standalone.sh $(or $(ARGS),write)
# ── the shape every other project uses ─────────────────────────────────────
# Aliases, not a second implementation: each one calls the same script the
# canonical target does.

View File

@@ -63,25 +63,26 @@ instructions for everything else. No cluster and no toolchain required.
```bash
make check # report host and config problems; changes nothing
make deps # install the toolchain (add `core` on a managed machine)
make cluster up # build the cluster for the active profile
make cluster up # cluster + registry + the profile's addons
```
`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:
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 registry status # prints: endpoint localhost:<port>
make check # ... registry endpoint localhost:<port>
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:
collide — nothing to configure. `make check` lists it; `bash ctrl/ports.sh persist`
pins it into `ctrl/.env` if you want it fixed:
```bash
make ports show # HTTP / HTTPS / TILT / REGISTRY
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
@@ -151,9 +152,8 @@ than something every rig needs. Copy one to use it:
```bash
cp ctrl/env.d/data.env.example ctrl/env.d/data.env
PROFILE=data make cluster up
PROFILE=data make addons install
make addons # what the active profile wants, and what exists
PROFILE=data make cluster up # installs the profile's addons too
PROFILE=data make check # what the profile wants, and what exists
```
The **cluster itself** is one file, `ctrl/k8s/kind-config.yaml.tpl` (one node).

View File

@@ -13,8 +13,8 @@ PROFILE=
# CLUSTER=
# Host ports. LEAVE UNSET — they derive from the directory name so several
# environments coexist without negotiating (see ctrl/ports.sh). `make ports`
# shows this environment's block; `make ports persist` writes it here so it stops
# environments coexist without negotiating (see ctrl/ports.sh). `make check`
# shows this environment's block; `bash ctrl/ports.sh persist` writes it here so it stops
# being derived and becomes fixed. Set a value only to override.
# HTTP_PORT=
# HTTPS_PORT=

View File

@@ -10,6 +10,13 @@
set -euo pipefail
cd "$(dirname "$0")"
# `check mem` goes deeper on memory than the summary below: how far allocation
# really climbs, and the WSL .wslconfig backup/restore.
if [ "${1:-}" = mem ]; then
shift
exec bash ./mem.sh "${@:-status}"
fi
DEPS_IMAGE="${DEPS_IMAGE:-$(basename "$(cd .. && pwd)")-deps}"
# Host detection. Prefer running it bare — it needs no dependencies beyond
@@ -25,7 +32,6 @@ echo
echo "config"
echo " profile ${PROFILE_NAME} (nodes=${NODES})"
echo " cluster ${CLUSTER} (context ${KUBECONTEXT})"
echo " registry ${REGISTRY_MODE}"
echo " ingress ${INGRESS_MODE}"
if [ ! -f ./.env ]; then
@@ -175,7 +181,7 @@ fi
# because docker reports a clash halfway through, as an opaque
# "failed to bind host port ...: address already in use".
echo
echo "ports (block derived from the directory name — see 'make ports')"
echo "ports (block derived from the directory name; pin it: bash ctrl/ports.sh persist)"
port_busy() {
if command -v ss >/dev/null 2>&1; then
@@ -216,3 +222,13 @@ if [ "$clash" -eq 1 ]; then
echo " override the clashing one in ctrl/.env, e.g. HTTP_PORT=21080"
echo " (or rename this directory — the whole block follows the name)"
fi
# What `make cluster up` wires in beside the cluster. Both are set up by it —
# listed here only so there is nothing to run just to look.
echo
echo "registry"
bash ./registry.sh status | sed 's/^/ /'
echo
echo "addons"
bash ./addons.sh list | sed 's/^/ /'

View File

@@ -262,7 +262,7 @@ detect_wsl() {
echo " wslconfig memory set: $(grep -E '^\s*memory\s*=' "$wcfg" | tr -d ' ')"
else
MANUAL+=("Cap/raise the WSL VM memory — see what is set versus what booted:
make mem status
make check mem
It prints the edit to make and the command to apply it.")
fi
}

View File

@@ -124,7 +124,7 @@ done
note "one derivation, not three"
# The Makefile used to compute the cluster name itself and sed TILT_PORT out of
# ctrl/.env — a second derivation of values lib/config.sh already owns, which
# could disagree with it after `make ports persist`. It now reads ports.sh
# could disagree with it after `ports.sh persist`. It now reads ports.sh
# active. Nothing structurally prevents the sed coming back, so the agreement is
# asserted against the real `make -n` output rather than against the source.
# --no-print-directory and a grep, not `tail -1`: run from `make selftest` this
@@ -162,7 +162,7 @@ note "ports are stable across versions"
# Not a change-detector. The block is derived, never stored, so if the
# derivation shifts then every EXISTING environment's ports move underneath it —
# a running cluster keeps its old ports while rig starts reporting new ones, and
# `make ports` stops describing reality. Anchored to three known names.
# `ports.sh show` stops describing reality. Anchored to three known names.
check "derive_port_base rig" "20310" "$(derive_port_base rig)"
check "derive_port_base foo" "21690" "$(derive_port_base foo)"
check "derive_port_base my-proj" "21030" "$(derive_port_base my-proj)"

View File

@@ -1,215 +0,0 @@
#!/usr/bin/env bash
# Prepare a machine to run rig, and say plainly what worked, what was already
# done, and what is left for a human.
#
# This is the grouped entry point: `make setup`. Every step is idempotent and
# independently checked, so running it twice is safe and running it on a
# half-configured machine finishes the job rather than starting over.
#
# It deliberately does NOT abort on the first failure. A setup script that dies
# at step 2 hides the fact that steps 4 and 5 were also going to fail — and on
# an unfamiliar machine, the full picture is the whole point. Failures are
# collected and reported together, and the exit code reflects the worst outcome.
#
# Usage:
# setup.sh # host checks + the dev toolchain
# setup.sh core # kubectl and jq only — no cluster tooling
# setup.sh --cluster # ...and bring the cluster up
set -euo pipefail
cd "$(dirname "$0")"
source ./lib/config.sh
load_config
WITH_CLUSTER=0
# Cluster tooling is not wanted everywhere: a managed or corporate-issued
# machine may legitimately want kubectl and nothing that builds clusters.
TIER=dev
for a in "$@"; do
case "$a" in
core|dev) TIER="$a" ;;
--cluster) WITH_CLUSTER=1 ;;
*) echo "unknown option: $a" >&2; exit 1 ;;
esac
done
if [ "$TIER" = "core" ] && [ "$WITH_CLUSTER" -eq 1 ]; then
echo "core tier installs no cluster tooling, so --cluster cannot work" >&2
exit 1
fi
# ── step framework ─────────────────────────────────────────────────────────
# Statuses are deliberately distinct: "already" and "done" both mean success but
# tell you very different things about the machine you are on.
STEP_NAMES=()
STEP_STATUS=()
STEP_NOTE=()
WORST=0
record() {
STEP_NAMES+=("$1"); STEP_STATUS+=("$2"); STEP_NOTE+=("${3:-}")
# Only a genuine failure is a non-zero exit. "manual" means the machine is
# fine and you have something to do — reporting that as an error makes the
# whole run look broken and trains people to ignore the output.
[ "$2" = "fail" ] && WORST=1 || true
local mark
case "$2" in
already) mark=" ok " ;;
done) mark=" done " ;;
skip) mark=" skip " ;;
manual) mark="MANUAL" ;;
fail) mark=" FAIL " ;;
esac
printf "[%s] %-22s %s\n" "$mark" "$1" "${3:-}"
}
# ── steps ──────────────────────────────────────────────────────────────────
step_host() {
local out
if ! out=$(bash ./deps.sh detect 2>&1); then
record host fail "detection failed"
return
fi
# Anything flagged with '!' needs a human; surface the count here
# and the detail below rather than burying it.
local warns; warns=$(echo "$out" | grep -c '^\s*!' || true)
HOST_DETAIL="$out"
if [ "$warns" -gt 0 ]; then
record host manual "$warns item(s) need attention — see below"
else
record host already "no problems detected"
fi
}
step_toolchain() {
local want="kubectl jq"
[ "$TIER" = "dev" ] && want="$want kind tilt"
local missing=""
for b in $want; do
command -v "$b" >/dev/null 2>&1 || missing="$missing $b"
done
if [ -z "$missing" ]; then
record toolchain already "$TIER: $want"
return
fi
if bash ./deps.sh install "$TIER" >/tmp/rig-deps.$$ 2>&1; then
local still=""
for b in $want; do
[ -x "${OUT_BIN:-$HOME/.local/bin}/$b" ] || still="$still $b"
done
if [ -n "$still" ]; then
record toolchain fail "still missing:$still (see /tmp/rig-deps.$$)"
else
record toolchain done "$TIER, installed:$missing"
rm -f "/tmp/rig-deps.$$"
fi
else
record toolchain fail "install failed — see /tmp/rig-deps.$$"
fi
}
step_path() {
local bin="${OUT_BIN:-$HOME/.local/bin}"
case ":$PATH:" in
*":$bin:"*) ;;
*) record path manual "add to ~/.bashrc: export PATH=\"$bin:\$PATH\""; return ;;
esac
if grep -qs "$bin" "$HOME/.bashrc" "$HOME/.profile" 2>/dev/null; then
record path already "$bin on PATH and persisted"
else
record path manual "on PATH now, but not persisted in ~/.bashrc"
fi
}
step_docker() {
if ! command -v docker >/dev/null 2>&1; then
record docker fail "no docker cli — this is the one prerequisite rig cannot install"
return
fi
if docker info >/dev/null 2>&1; then
record docker already "$(docker version --format '{{.Server.Version}}' 2>/dev/null)"
else
record docker fail "daemon unreachable (in the docker group? logged out and back in?)"
fi
}
step_ports() {
local busy=""
for entry in "HTTP:$HTTP_PORT" "HTTPS:$HTTPS_PORT" "TILT:$TILT_PORT" "REGISTRY:$REGISTRY_PORT"; do
local p="${entry#*:}"
if command -v ss >/dev/null 2>&1 && ss -ltn "sport = :$p" 2>/dev/null | grep -q LISTEN; then
busy="$busy ${entry%%:*}($p)"
fi
done
if [ -n "$busy" ]; then
record ports fail "in use:$busy — override in ctrl/.env or rename the directory"
else
record ports already "$HTTP_PORT-$REGISTRY_PORT free"
fi
}
step_cluster() {
if [ "$TIER" = "core" ]; then
record cluster skip "core tier — no cluster tooling on this machine"
return
fi
if [ "$WITH_CLUSTER" -ne 1 ]; then
record cluster skip "not requested (--cluster)"
return
fi
if kind get clusters 2>/dev/null | grep -qx "$CLUSTER"; then
record cluster already "'$CLUSTER' exists"
return
fi
if bash ./cluster.sh up >/tmp/rig-cluster.$$ 2>&1; then
record cluster done "'$CLUSTER' created"
rm -f "/tmp/rig-cluster.$$"
else
record cluster fail "see /tmp/rig-cluster.$$"
fi
}
# ── run ────────────────────────────────────────────────────────────────────
echo "setting up '$CLUSTER'"
echo
HOST_DETAIL=""
step_host
step_toolchain
step_path
step_docker
step_ports
step_cluster
echo
if [ -n "$HOST_DETAIL" ]; then
echo "host detail"
echo "$HOST_DETAIL" | sed 's/^/ /'
echo
fi
# Repeat only what still needs action, so the tail of the output is a to-do list
# rather than a transcript.
outstanding=0
for i in "${!STEP_NAMES[@]}"; do
case "${STEP_STATUS[$i]}" in
fail|manual)
[ "$outstanding" -eq 0 ] && echo "outstanding:"
outstanding=1
printf " %-8s %-16s %s\n" "${STEP_STATUS[$i]}" "${STEP_NAMES[$i]}" "${STEP_NOTE[$i]}"
;;
esac
done
if [ "$outstanding" -eq 0 ]; then
echo "ready. next: make cluster up && make docs"
else
echo
echo "(nothing was aborted — every step ran so the list above is complete)"
fi
exit "$WORST"

View File

@@ -267,7 +267,7 @@
<pre><code><span class="c"># then, in the environment directory:</span>
make check <span class="c"># is this machine ready? reports, never fixes</span>
make deps <span class="c"># install the pinned toolchain</span>
make cluster up <span class="c"># build the cluster for the active profile</span>
make cluster up <span class="c"># cluster + registry + addons; ports derive by themselves</span>
</code></pre>
<p>Read <code>make check</code> before <code>make deps</code>. It never changes
anything — it prints what it found and, at the end, the steps it cannot perform
@@ -288,20 +288,14 @@ make cluster up <span class="c"># build the cluster for the active profile</spa
one failure at a time.</p>
<pre><code>make check</code></pre>
<h3>2 &middot; make setup</h3>
<p>Does the preparation that can be automated: installs the pinned
toolchain if it is missing, checks PATH, Docker, and this environment's
ports. Every step is independently checked, so running it twice is safe and
running it half-configured finishes the job.</p>
<p>It <b>does not stop at the first failure</b>. A setup script that dies at
step two hides that steps four and five would also have failed, and on an
unfamiliar machine the complete list is the point. The tail of the output is
a to-do list of only what is outstanding.</p>
<pre><code>make setup <span class="c"># host + toolchain</span>
</code></pre>
<h3>2 &middot; make deps</h3>
<p>Installs the pinned toolchain — only what is missing — and tells you
if its directory is not on PATH yet. Running it twice is safe.</p>
<pre><code>make deps</code></pre>
<h3>3 &middot; make cluster up</h3>
<p>Builds the cluster for the active profile. It prints what the profile
<p>Builds the cluster, starts its registry and installs the profile's
addons — there is nothing else to run first. It prints what the profile
locks in <i>before</i> spending the time, because the kind config is
fixed at creation and cannot be changed afterwards.</p>
<p>Re-running is safe and, more importantly, <b>convergent</b>: if a first
@@ -322,17 +316,17 @@ make cluster reset <span class="c"># destroy and rebuild — how an
<h3>Checking on things</h3>
<dl>
<dt>make cluster list</dt><dd>Every cluster on the machine, its memory cost and its port block. The usual reason a new one will not start is an old one you forgot about; <code>make cluster free</code> frees them without deleting.</dd>
<dt>make ports</dt><dd>This environment's port block, and whether each is derived or overridden.</dd>
<dt>make registry</dt><dd>Which of the four registry modes is active, and where it points.</dd>
<dt>make check</dt><dd>Also this environment's port block, its registry and the profile's addons.</dd>
<dt>make check mem</dt><dd>Memory in depth: what caps it, how far it really climbs, and on WSL the <code>.wslconfig</code> backup and restore.</dd>
</dl>
<h3>Running more than one</h3>
<p>Copy the directory, rename it, and repeat from step 2. Cluster name,
<p>Copy the directory, rename it, and run <code>make cluster up</code>. Cluster name,
context, image tags and the port block all follow the directory name, so
the second environment collides with nothing and neither one's teardown can
reach the other.</p>
<pre><code>cp -r rig ../platform-v2 &amp;&amp; cd ../platform-v2
make setup &amp;&amp; make cluster up
make cluster up
</code></pre>
</div>
</section>
@@ -370,16 +364,15 @@ make setup &amp;&amp; make cluster up
</table>
<pre><code>make deps core <span class="c"># kubectl and jq only — nothing that creates a cluster</span>
make deps <span class="c"># dev, the default</span>
make setup core <span class="c"># same distinction, via setup</span>
</code></pre>
<p>Testing <i>in situ</i> on a managed machine is still possible — install
the <code>dev</code> tier deliberately when you need it. The point is that
it should be a decision rather than a side effect of running setup.</p>
it should be a decision rather than a side effect of installing.</p>
<p>The documentation itself needs neither tier: <code>make docs</code>
wants only Docker.</p>
<h3>Air-gapped</h3>
<pre><code>make deps-image full <span class="c"># bakes every binary into the image</span>
<pre><code>make deps image full <span class="c"># bakes every binary into the image</span>
docker save …-deps:full | gzip &gt; rig.tgz
<span class="c"># carry that one file in, then:</span>
docker load &lt; rig.tgz &amp;&amp; make cluster up PROFILE=offline <span class="c"># from env.d/offline.env.example</span>
@@ -403,8 +396,8 @@ docker load &lt; rig.tgz &amp;&amp; make cluster up PROFILE=offline <span clas
<dt>registry + images</dt><dd>Named after the environment, so two copies never share one.</dd>
</dl>
<p>Two copies therefore never collide, and neither one's
<code>make cluster down</code> can touch the other. <code>make ports</code>
shows the block; <code>make ports persist</code> freezes it into
<code>make cluster down</code> can touch the other. <code>make check</code>
shows the block; <code>bash ctrl/ports.sh persist</code> freezes it into
<code>ctrl/.env</code> if you want it fixed rather than derived.</p>
<h3>Configuration layers</h3>

View File

@@ -360,7 +360,7 @@ detect_wsl() {
echo " wslconfig memory set: $(grep -E '^\s*memory\s*=' "$wcfg" | tr -d ' ')"
else
MANUAL+=("Cap/raise the WSL VM memory — see what is set versus what booted:
make mem status
make check mem
It prints the edit to make and the command to apply it.")
fi
}

View File

@@ -50,8 +50,7 @@ compose, the same dependency installs as a rig addon of that name:
```bash
cd rig
PROFILE=data make cluster up
PROFILE=data make addons install
PROFILE=data make cluster up # installs the addons too
```
The two paths are deliberately separate — compose for a laptop, helm for a