chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
The runner host deploys with main
.knotless/workflows/deploy.yml+26−1
| @@ -26,12 +26,19 @@ | ||
# an app password of theirs granted to pushes to main as release.yml's is. | ||
# It is then `docker pull knotless.dev/chadtmiller.com/knotless/knotless-server`: | ||
# one image for serve, the pages, the runner and the triager, as here. | ||
# | ||
# Last, the runner host (deploy/runner-host) takes the same image, copied | ||
# from this host only when its runner's build differs, and is restarted | ||
# with the settings below, so the runner that lands other repositories' | ||
# merge queues reads their rules as main does. It is reached with | ||
# RUNNER_HOST_SSH_KEY, granted to pushes to main alone, which its root | ||
# takes only from this host's addresses. | ||
on: | ||
push: | ||
refs: [refs/heads/main] | ||
superseded: finish | ||
image: docker:28-cli | ||
secrets: [DEPLOY_SSH_KEY, RELEASE_PASSWORD] | ||
secrets: [DEPLOY_SSH_KEY, RELEASE_PASSWORD, RUNNER_HOST_SSH_KEY] | ||
env: | ||
KNOTLESS_HOST: root@knotless.dev | ||
KNOTLESS_DOMAIN: knotless.dev | ||
| @@ -58,6 +65,17 @@ env: | ||
# The runner host's account (deploy/runner-host), which a new public | ||
# repository names unless its owner names others: it runs anyone's. | ||
KNOTLESS_DEFAULT_RUNNER_DID: did:plc:4bocpkn5zkwe4wuu4plrj5kt | ||
# That host, deployed after this one (deploy/runner-host/deploy.sh), as | ||
# runner.knotless.dev. It lands the merge queues of the repositories | ||
# that name it, and runs knotless's pulls alone, under runc for the | ||
# owner and their organization (README.md there). | ||
KNOTLESS_RUNNER_HOST: root@runner.knotless.dev | ||
KNOTLESS_RUNNER_DOMAIN: runner.knotless.dev | ||
KNOTLESS_RUNNER_DID: did:plc:4bocpkn5zkwe4wuu4plrj5kt | ||
KNOTLESS_RUNNER_ARGS: --queue --pulls-only chadtmiller.com/knotless --unmetered did:plc:bcgltzqazw5tb6k2g3ttenbj --unmetered did:plc:e7rftrdyz5e2rw4y6ocszew2 --trust did:plc:bcgltzqazw5tb6k2g3ttenbj --trust did:plc:e7rftrdyz5e2rw4y6ocszew2 --pull-jobs 2 | ||
KNOTLESS_RUNNER_CPUS: "4" | ||
KNOTLESS_RUNNER_JOBS: "2" | ||
KNOTLESS_RUNNER_MEMORY: "7" | ||
# The oldest client this asks for: 0.6.0 deletes a deleted ref's record | ||
# and starts a new ref at the time, and an older client making a branch | ||
# again under a name deleted within the day can have its pushes refused. | ||
| @@ -194,3 +212,10 @@ steps: | ||
tar -x -C "$dir" | ||
knotless publish "$REPO" knotless-server "$VERSION" --oci "$dir" --commit "$SHA" | ||
' | ||
- name: runner host | ||
run: | | ||
[ ! -e ~/.moved ] && [ -e ~/.up ] || exit 0 | ||
[ -n "$RUNNER_HOST_SSH_KEY" ] || { echo "no RUNNER_HOST_SSH_KEY: not deploying the runner host"; exit 0; } | ||
printf '%s\n' "$RUNNER_HOST_SSH_KEY" > ~/.ssh/runner_host && chmod 600 ~/.ssh/runner_host | ||
printf 'Host %s\n IdentityFile ~/.ssh/runner_host\n' "${KNOTLESS_RUNNER_HOST#*@}" >> ~/.ssh/config | ||
KNOTLESS_RUNNER_IMAGE_FROM="$KNOTLESS_HOST" deploy/runner-host/deploy.sh | ||
deploy/runner-host/deploy.sh+19−5
| @@ -23,7 +23,11 @@ | ||
# - optional: KNOTLESS_RUNNER_ARGS, more of its command line (`--queue`); | ||
# KNOTLESS_RUNNER_JOBS (4), _CPUS (2), _MEMORY (3, GiB), _TIMEOUT | ||
# (3600 s), _ALLOWANCE (2000) and _PRIVATE_ALLOWANCE (500), as | ||
# docker-compose.yml passes them; KNOTLESS_LOG (info). | ||
# docker-compose.yml passes them; KNOTLESS_LOG (info); | ||
# - optional: KNOTLESS_RUNNER_IMAGE_FROM, an SSH destination whose | ||
# knotless:current to run rather than building here, copied only when | ||
# its runner's build differs: main's deploy sets it to the main host, | ||
# so both run the same knotless (.knotless/workflows/deploy.yml). | ||
# | ||
# The image is built on the host, from this checkout's HEAD as `git | ||
# archive` gives it (so commit first): a build driven over SSH by a local | ||
| @@ -40,10 +44,20 @@ SSH="ssh -o StrictHostKeyChecking=accept-new $DEST" | ||
COMMIT="$(git rev-parse HEAD 2>/dev/null || echo local)" | ||
| ||
if [ -n "${KNOTLESS_RUNNER_IMAGE_FROM:-}" ]; then | ||
# A box too small to build knotless takes the image another host built. | ||
echo "==> copying knotless:current from $KNOTLESS_RUNNER_IMAGE_FROM to $DEST" | ||
ssh -o StrictHostKeyChecking=accept-new "$KNOTLESS_RUNNER_IMAGE_FROM" 'docker save knotless:current | gzip -1' | | ||
$SSH 'gunzip | docker load -q' | ||
# A box too small to build knotless, or a deploy of main, takes the image | ||
# another host built, unless the runner here is that build already: as | ||
# the main host's deploy does (deploy/deploy.sh), a runner whose build | ||
# is the same is left running, since a restart cancels its runs. | ||
FROM="ssh -o StrictHostKeyChecking=accept-new $KNOTLESS_RUNNER_IMAGE_FROM" | ||
PRINT='docker run --rm --entrypoint cat knotless:current /etc/knotless-run.fingerprint' | ||
NEW=$($FROM "$PRINT" 2>/dev/null || true) | ||
OLD=$($SSH "$PRINT" 2>/dev/null || true) | ||
if [[ $NEW =~ ^[0-9a-f]{64}$ ]] && [ "$NEW" = "$OLD" ]; then | ||
echo "==> its runner is ${NEW:0:12} on $KNOTLESS_RUNNER_IMAGE_FROM too: keeping its image" | ||
else | ||
echo "==> copying knotless:current (${NEW:0:12}, here ${OLD:0:12}) from $KNOTLESS_RUNNER_IMAGE_FROM to $DEST" | ||
$FROM 'docker save knotless:current | gzip -1' | $SSH 'gunzip | docker load -q' | ||
fi | ||
else | ||
echo "==> building knotless at ${COMMIT:0:12} on $DEST" | ||
git archive --format=tar HEAD | | ||
deploy/runner-host/README.md+25−0
| @@ -204,6 +204,31 @@ elsewhere](../../docs/design/runner.md#where-pushes-run-elsewhere)). The | ||
first pull over an empty cache builds in full; the ones after start from | ||
what it left, the `test` workflow's stored coverage runs among it. | ||
| ||
## Deployed with main | ||
| ||
Each deploy of main deploys this host too, last | ||
(`.knotless/workflows/deploy.yml`, its `runner host` step), so the | ||
runner that lands other repositories' merge queues reads their records | ||
as main does: an older one ejects a pull whose rule holds what it does | ||
not know (`what this version does not know: gates; update knotless`). | ||
It runs `deploy.sh` with `KNOTLESS_RUNNER_IMAGE_FROM` the main host, | ||
whose image it copies only when its runner's build (the fingerprint | ||
the main host's deploy compares) differs from this host's: a deploy | ||
that leaves the runner as it was restarts nothing here, as on the main | ||
host. Its settings are the `KNOTLESS_RUNNER_*` in that workflow, which | ||
`deploy/local.env` repeats for a deploy by hand. | ||
| ||
It reaches the host with `RUNNER_HOST_SSH_KEY`, a key of its own, | ||
granted to pushes to main alone (`knotless secret … set | ||
RUNNER_HOST_SSH_KEY --ref refs/heads/main`). Root takes it only from the | ||
main host's addresses, as `setup.sh` installs its public half: | ||
| ||
```sh | ||
KNOTLESS_RUNNER_DEPLOY_KEY="ssh-ed25519 AAAA… knotless deploy of main" \ | ||
KNOTLESS_RUNNER_DEPLOY_FROM="178.104.222.99,2a01:4f8:c015:4df4::/64" \ | ||
deploy/runner-host/setup.sh | ||
``` | ||
| ||
## Running it | ||
| ||
- **Pause someone:** edit `/etc/knotless/paused.json` on the host, as | ||
deploy/runner-host/setup.sh+16−1
| @@ -26,7 +26,8 @@ | ||
# through NAT rules gVisor does not apply, so runs name public ones. | ||
# | ||
# It ends by checking from inside a gVisor container on that network that | ||
# the internet answers and the metadata service and private ranges do not. | ||
# the internet answers and the metadata service and private ranges do not; | ||
# then, given KNOTLESS_RUNNER_DEPLOY_KEY, lets main's deploy in with it. | ||
| ||
set -euo pipefail | ||
cd "$(dirname "$0")/../.." | ||
| @@ -180,3 +181,17 @@ docker run --rm --runtime runsc --network knotless-runs \ | ||
dmesg 2>/dev/null | head -1 | grep -q gVisor && echo "kernel: gVisor" || echo "kernel: NOT gVisor" | ||
' | ||
HOST | ||
| ||
# The key main's deploy reaches this host with (.knotless/workflows/ | ||
# deploy.yml, RUNNER_HOST_SSH_KEY), its public half: root takes it only | ||
# from the main host's addresses, KNOTLESS_RUNNER_DEPLOY_FROM, so the key | ||
# alone reaches nothing from anywhere else. | ||
if [ -n "${KNOTLESS_RUNNER_DEPLOY_KEY:-}" ]; then | ||
from="${KNOTLESS_RUNNER_DEPLOY_FROM:?KNOTLESS_RUNNER_DEPLOY_KEY takes KNOTLESS_RUNNER_DEPLOY_FROM, the addresses of the main host}" | ||
printf 'from="%s" %s\n' "$from" "$KNOTLESS_RUNNER_DEPLOY_KEY" | | ||
ssh -o StrictHostKeyChecking=accept-new "$DEST" ' | ||
f=/root/.ssh/authorized_keys | ||
read -r line | ||
grep -qxF "$line" "$f" || printf "%s\n" "$line" >> "$f" | ||
' | ||
fi | ||