Skip to content

feat(cluster): burrow cluster bootstrap turns a bare VPS into a Burrow cluster#203

Merged
incognick merged 2 commits into
mainfrom
feat/vps-cluster-bootstrap
Jul 3, 2026
Merged

feat(cluster): burrow cluster bootstrap turns a bare VPS into a Burrow cluster#203
incognick merged 2 commits into
mainfrom
feat/vps-cluster-bootstrap

Conversation

@incognick

Copy link
Copy Markdown
Contributor

Adds burrow cluster bootstrap, run once on a VPS, which resolves the public IP, installs k3s with the SANs and external IP the laptop needs, deploys burrowd (reusing the burrow install path, which also mints the scoped agent credential per ADR-0038), and prints a burrow join <token> line for the user to run on their laptop. This is Phase 2 of ADR-0044 (single-VPS k3s), producing the token that Phase 1's burrow join consumes.

What it does

  1. Resolves the public IP — the --public-ip flag if given, otherwise auto-detected behind a seam (an echo service, ipify by default). Either way it validates the result is a globally routable address and stops clearly (pointing at --public-ip) otherwise.
  2. Installs k3s behind a seam, idempotently (skips when k3s is already installed and its API answers). The install command is built as an inspectable value carrying the critical flags: --tls-san <ip>, --node-external-ip <ip>, --write-kubeconfig-mode 0644, and --disable traefik. servicelb is left enabled as the free single-node LoadBalancer (ADR-0043).
  3. Waits for the k3s API with a bounded retry.
  4. Deploys burrowd by reusing runInstall against the local k3s admin kubeconfig, so there is no duplicate install logic and the scoped burrow-agent credential (ADR-0038) the laptop's burrow join later reads is minted by the same manifests.
  5. Emits the join token — the local k3s admin kubeconfig (cluster CA + admin client cert/key) with its server rewritten from https://127.0.0.1:6443 to https://<public-ip>:6443, encoded via the ADR-0044 jointoken codec, printed as a burrow join <token> line with an admin-grade warning, the laptop next steps, and the :6443/:80/:443 firewall reminder.

Traefik

Disabled: k3s ships traefik by default, but Burrow provisions ingress-nginx via burrow cluster ingress install, and two controllers contending for :80/:443 is the misconfiguration to avoid. servicelb is kept.

Testing

The full flow needs a real k3s and is not unit-tested end to end, but the pieces are, behind the seams: public-IP resolution (explicit flag, auto-detect, and the public-address validation/error paths), the k3s install-command construction (asserting the required flags and that servicelb is not disabled), the install-or-skip idempotency, and the join-token assembly round-tripping through jointoken.Decode with the server rewritten to the public IP. The light gate (build, vet, gofmt, tests, SPDX) passes.

…w cluster

Add `burrow cluster bootstrap`, run once on a VPS, which resolves the public
IP, installs k3s with the SANs and external IP the laptop needs, deploys
burrowd (reusing the install path, which also mints the scoped agent
credential per ADR-0038), and prints a `burrow join <token>` line for the
user to run on their laptop.

The token is the local k3s admin kubeconfig with its server rewritten from the
loopback address k3s writes to the public IP, encoded via the ADR-0044 codec.
k3s is installed with --tls-san and --node-external-ip so the API-server
certificate is valid for the public IP the laptop connects through,
--write-kubeconfig-mode 0644 so the bootstrap can read the admin kubeconfig,
and --disable traefik so Burrow's ingress-nginx owns ingress; servicelb is
left enabled as the free single-node LoadBalancer.

The public-IP detector and the k3s installer are behind seams, so the pieces
are unit-tested: public-IP resolution (flag, auto-detect, and the
public-address validation), the install-command construction, the
install-or-skip idempotency, and the join-token assembly round-tripping
through jointoken with the server rewritten to the public IP. The full flow
needs a real k3s and is not unit-tested end to end.

Signed-off-by: Nicholas Phillips <nsphilli@gmail.com>
@incognick incognick added the pr-ready A PR is open and ready for review label Jul 3, 2026
…p-clean

On the VPS, `burrow cluster bootstrap` deploys burrowd by reusing the install
path, which printed the laptop-oriented "connect your agent" guidance and
recorded a local ~/.burrow environment handle — both of which contradict
bootstrap's own "copy this token to your laptop" message.

Add a clusterOnly field to installArgs. When set, the install performs only its
cluster-side effects (deploy burrowd, and mint the scoped burrow-agent
credential via the manifests) and skips the laptop-oriented local bookkeeping:
it records no ~/.burrow handle and prints no post-install guidance, and an
already-installed cluster returns without the local join. bootstrap sets the
flag, so on the VPS the only output is the k3s/burrowd progress and the
join-token block. Normal `burrow install` leaves it false and is unchanged.

The now-dead bootstrap --environment flag (it named the local handle, which is
no longer recorded on the VPS) is removed.

Signed-off-by: Nicholas Phillips <nsphilli@gmail.com>
@incognick incognick enabled auto-merge July 3, 2026 22:13
@incognick incognick added this pull request to the merge queue Jul 3, 2026
Merged via the queue into main with commit a262093 Jul 3, 2026
5 checks passed
@incognick incognick deleted the feat/vps-cluster-bootstrap branch July 3, 2026 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-ready A PR is open and ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant