~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
78 lines · 6.3 KB Raw History

Deploying a release to production

The long form of the gateway deploy: the build, the acceptance step, rollback, the canary and the one-time host items. Short path in CONTRIBUTING.

flowchart TD
  tag["git tag v*"] --> gh["GitHub CI<br/>gate, pins, binaries, guest image"]
  main["push to main"] --> gh
  gh -->|"publish"| bucket["Spaces bucket<br/>releases/tag, main/commit"]
  bucket --> deploy["scripts/deploy.sh"]
  deploy --> gw["gateway host"]
  deploy --> bidder["bidder host"]

Three deploy shapes, and they differ:

ShapeWhat happensWhat survives
Routine gateway deploy (scripts/deploy.sh on an installed gateway)upgrade --binary --sha256, then install gateway again; the core adopts every installed and transient unit and rolls the kcp slot only when kcp's argv or binary changedState dir and its kcp objects, the root OpenBao (requester repo key, sessions), the gateway requester's DID and its association record, gateway sessions, running components. Read on prod: web session across rc8 to rc9, requester DID and association across rc11 to rc21 with no new claim
Routine bidder upgrade (as the account: upgrade --binary <path> --sha256 <digest>, then the same install bidder again)The bidder's core restarts on the new binary; components are replaced only when the spec or the component set changedThe bidder's state dir, its OpenBao (repo key), the bidder DID and handle, its association record, its PDS repo. Read on prod: Bob's bidder DID and association across rc11 to rc21 with no new claim
Fresh install (install gateway or install bidder on an empty host, or a lost or purged state dir)First install; new keys generatedNothing. The identity gets a new DID and needs one association claim again (scripts/associate-bidder.ts with --bidder-did or --requester-did; the application's association watch approves it, with no manual approvedAssociations patch)

The policy is still "nothing is guaranteed": a change may deliberately wipe state, and there is no migration or backward compatibility to plan for. Losing sessions, VMs, clusters, claims or receipts is acceptable; what exists, this table says.

# 1. confirm the commit's run is green on GitHub (.github/workflows/ci.yml)
# 2. build the release
C=$(git rev-parse HEAD)
scripts/build-socialweb-computer.sh --platform linux/amd64 --commit $C
B=~/.tmp/socialweb-computer-build/release/$C/socialweb-computer-linux-amd64; SHA=$(sha256sum $B | cut -d' ' -f1)
# 3. gateway (socialweb.computer): ship, install the first time or upgrade and install again after, write the caddy sites
BINARY=$B SHA256=$SHA SSH_KEY=~/.ssh/id_ed25519_no_password \
  GATEWAY_ENV_FILE=~/.tmp/deploy/gateway.env GATEWAY_SPEC_FILE=~/.tmp/deploy/gateway-spec.yaml scripts/deploy.sh
# 4. bidder: stage the binary, then upgrade it as the account
R=/var/tmp/swc-release/socialweb-computer-${C:0:8}; sudo install -m 0755 $B $R
sudo runuser -u swc-bidder -- env XDG_RUNTIME_DIR=/run/user/$(id -u swc-bidder) \
  CONFIG_PATH_SOCIALWEB_COMPUTER=/var/lib/socialweb-computer/swc-bidder/config.json $R upgrade --binary $R --sha256 $SHA

Every prod bidder runs the policy bidder-tangled-vouch: it is the MarketBidder default when spec.policy is unset, and install bidder writes bidder-policy to config.json (bidder-tangled-vouch unless --bidder-policy names another), which upgrade and restarts keep. open is insecure and runs only when set explicitly (--bidder-policy open or spec.policy: open); never on a prod bidder. A requester gets bids only when the bidder operator vouches it (sh.tangled.graph.vouch, rkey the requester's DID): bob and john vouch alice, the acceptance requester (docs/acceptance/0001-auth-modes.md, Bidder policy).

Verify the deployment by scaling a tenant cluster from zero and back:

GW=https://k8s.socialweb.computer AUD=did:web:k8s.socialweb.computer K=computer.socialweb.k8s
# apply the Job below to the canary cluster, then poll it (README: Apply objects and read Jobs without a kubeconfig)
jq -n '{cluster: "canary", manifest: {apiVersion: "batch/v1", kind: "Job",
  metadata: {name: "scale-check", namespace: "default"},
  spec: {backoffLimit: 0, template: {spec: {restartPolicy: "Never",
    containers: [{name: "run", image: "docker.io/library/busybox:1.36.1", command: ["sh", "-c", "echo up"]}]}}}}}' |
  curl -sS -X POST "$GW/xrpc/$K.kubectlApplyServerSide" -H "Content-Type: application/json" \
    -H "Authorization: Bearer $(goat account service-auth --aud $AUD --lxm $K.kubectlApplyServerSide)" -d @- | jq -c '{kind, name}'
curl -sS "$GW/xrpc/$K.getJob?cluster=canary&namespace=default&name=scale-check&tailLines=50" \
  -H "Authorization: Bearer $(goat account service-auth --aud $AUD --lxm $K.getJob)" | jq -c '{phase, succeeded}'

A tenant cluster scales from zero when you apply a pod to it: the pod raises a NodeClaim, the cluster runs the RFP flow for a market VM, the node joins, and the pod runs. Deleting the pod returns the cluster to zero nodes and deletes the VM. Applying a Job on a cluster at zero nodes works the same way; poll getJob or watch #nodeClaim on subscribeClusters.

Roll back as the account with socialweb-computer rollback --state-dir <state> (or with CONFIG_PATH_SOCIALWEB_COMPUTER=<state>/config.json set).

Once per host, or when the item changes:

# guest image on a bidder host (pinned sha256 in internal/versions/versions.json)
scripts/build-guest-image.sh --target firecracker-x86_64 --out /var/tmp/guest-image
sudo install -d -m 0755 /var/lib/socialweb-computer/guest-image && sudo install -m 0644 /var/tmp/guest-image/firecracker-x86_64/{vmlinux,rootfs.ext4,image.json} /var/lib/socialweb-computer/guest-image/
# OAuth client scope on qr.fedfork.com (the did-key-associator frontend, a separate host); needed when a bidder writes a new record type
cd ../did-key-associator && SSH_KEY=~/.ssh/id_ed25519_no_password scripts/deploy.sh --static-only

The deploy inputs (gateway.env, gateway-spec.yaml) live on the orphan branch swc-deploy, in the worktree ~/.tmp/deploy. The credential files ~/.aliceoa_bsky_social_source and ~/.bobvmbuilder_bsky_social_source are mode 0600; never print, log, or commit their values.

See also