The website loop
This is golem deploying golem’s own docs. Build this Starlight site into a
container on one golem-managed box, push it to the golem-hosted registry, run it
as a Workload on a third, and curl the homepage for a 200.
It continues A registry on the fleet — the
registry, builder, and web guests must be up, golemd deployed, and the
registry serving on your 127.0.0.1:5000. Commands are nushell, from the repo
root.
The three boxes
| Box | scroll | Role |
|---|---|---|
kaiju | examples/registry/registry.emet | stores the image |
talos | examples/website/builder.emet | builds the site image and pushes it |
remora | examples/website/website.emet | pulls the image and serves it publicly |
builder.emet provisions podman and the insecure-registry drop-in — the box can
push, but building and pushing is a CI step, not a glyph. The scroll only makes
the box able to push.
website.emet runs the served container. It drops in the same insecure-registry
fragment, then a single public Workload — the golem-website image pulled
from the fleet registry, published on :80:
import Quadlet exposing ( image, tcp, Restart(..), Expose(..), Workload(..), workloadGlyphs )
registryEndpoint : StringregistryEndpoint = "10.0.2.2:5000"
-- insecureConfPath and insecureConfContents elided: the drop-in's path under-- /etc/containers/registries.conf.d, and its [[registry]] … insecure = true body.
website : Workloadwebsite = Workload { name = "golem-website" , image = image registryEndpoint "golem-website" "latest" , env = [] , ports = [ tcp 80 80 ] , volumes = [] , restart = Always , expose = Public }
websiteGlyphs : List GlyphwebsiteGlyphs = List.concat [ [ file { path = insecureConfPath , contents = insecureConfContents , mode = "0644" } ] , workloadGlyphs website ]
main : List Scrollmain = [ scroll { name = "web" , notifies = [ "golem-nftables.service" ] , glyphs = websiteGlyphs } ]expose = Public opens :80 to the world with one drop-in file, and pulls in
the nftables base that loads it, so the web scroll lowers to eleven glyphs:
main : List Scrollplanned scrolls (1): scroll `remora` (11 glyphs): * ensure file `/etc/containers/registries.conf.d/golem-registry.conf` (mode 0644) * ensure apt package `podman` installed * ensure file `/etc/containers/systemd/golem-website.container` (mode 0600) * enable + start systemd unit `golem-website.service` * ensure apt package `nftables` installed * ensure directory `/etc/nftables.d` (mode 0755) * ensure file `/etc/golem-nftables.conf` (mode 0755) * ensure file `/etc/nftables.d/00-base.nft` (mode 0644) * ensure file `/etc/systemd/system/golem-nftables.service` (mode 0644) * enable + start systemd unit `golem-nftables.service` * ensure file `/etc/nftables.d/public-golem-website-80.nft` (mode 0644) ↻ remora notifies golem-nftables.serviceThe last file is the whole opening: a complete table inet golem block accepting
:80, dropped into a directory the entrypoint conf includes. The six glyphs
above it are the base every exposed workload carries — the table, its entrypoint,
and the service that loads them. The ↻ line is the scroll’s notifies: one
reload at the end of the apply, after the drop-in is in place.
Run the loop
-
Build the site on your workstation.
Terminal window build-siteThe devenv script that runs
bun run buildinsites/website. It ends on Astro’s own summary and leaves the output insites/website/dist:[build] Complete! -
Ship the build context to the builder and push the image. This is the long step: the builder pulls a base image, runs the container build, and pushes every layer over the host gateway. Minutes, and mostly silent between layer lines.
Terminal window tar -C sites/website -cf - Containerfile nginx.conf dist | fleet ssh talos -- "mkdir -p site && tar -xf - -C site"fleet ssh talos -- "sudo podman build -t 10.0.2.2:5000/golem-website:latest site && sudo podman push 10.0.2.2:5000/golem-website:latest"The quoted
&&chains run in the guest’s bash over ssh, so nushell never sees them.podman buildends on the image id it just wrote, and the push ends on its digest:Writing manifest to image destination -
Check that the registry took it.
Terminal window curl -s http://127.0.0.1:5000/v2/_catalog{"repositories":["golem-website"]}That request went to your workstation’s
127.0.0.1:5000, which qemu forwards into the registry guest. The builder reached the same registry from inside its own guest at10.0.2.2:5000— the host gateway — which is how two SLIRP-isolated guests trade an image with no shared network between them. -
Serve it. The web box pulls the freshly-pushed image and starts serving:
Terminal window fleet plan examples/website/website.emet --hosts remorafleet apply examples/website/website.emet --hosts remoraThe plan is eleven installs against revision 1; the apply draws them settling and closes on one line under the host’s heading:
web ssh://golem@127.0.0.1:2252apply settled — revision 2 -
Curl the homepage for a 200. The web box’s
:80is published to your workstation on 8081:Terminal window curl -sI http://127.0.0.1:8081/ | lines | firstHTTP/1.1 200 OK
Golem’s documentation, built on a golem-provisioned builder, stored in a
golem-provisioned registry, pulled and served by a golem-provisioned web box.
curl -s http://127.0.0.1:8081/ shows <title>Golem | Golem</title> in the
markup.
Explore from here
- Re-deploy a docs change. Edit a page, rebuild, push a new
:latest, and re-apply the web scroll — the.containerglyph’s content id is unchanged (the tag is the same), so pin a new tag or a digest withimageAtto make the diff replace it. - Reverse the web box. Apply a
webscroll with an emptyglyphslist and watch golem stop the container, remove the quadlet, and close:80by deleting its one drop-in file — leaving every other opening’s file untouched. - Add a second served site. Write another public
Workloadon a different port and apply it alongside — two containers, two firewall openings, derived from their ports.
Where to next
- The Quadlet library — the
WorkloadandExposethis loop is built on. - A tour of the lichess fleet — the same shapes at fleet scale.
- Reversible reconcile — why reversing the web box is exact.