docs: fix Forgejo runner setup gaps in stage 3 step 6

- Distinguish the runner registration token from FORGEJO_TOKEN explicitly
  (easy to mix up, causes a confusing "registration token not found" error)
- Split register/daemon into two commands: register is one-shot and exits,
  running only it under --restart unless-stopped silently loops forever
  instead of ever listening for a job
- Add --userns=keep-id, needed so the container can open the rootless
  Podman socket (owned by k8s's host UID, not the container's remapped one)
- Note that <FORGEJO_USER>/<FORGEJO_TOKEN> are placeholders to replace,
  not literal syntax, since bash reads a bare <word> as redirection

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4YNpuC2bgT224suQLLJ7B
This commit is contained in:
CodeGit 2026-09-04 07:18:52 +01:00
parent bf6246d577
commit 89f738885c

View file

@ -302,22 +302,67 @@ doesn't share a blast radius with the cluster.
echo $XDG_RUNTIME_DIR # note this path, e.g. /run/user/1001 echo $XDG_RUNTIME_DIR # note this path, e.g. /run/user/1001
``` ```
2. Instance admin: `Site Administration → Actions → Runners`, confirm 2. Instance admin: `Site Administration → Actions → Runners`, confirm
Actions is enabled. Actions is enabled. `Site Administration` is a top-level menu only
visible to instance admin accounts (not just repo owners) — click your
profile avatar (top-right of any page) and look for it in the dropdown;
if it's not there, the account you're logged in as isn't an instance
admin. Inside, it's a left-hand sidebar (Dashboard, Users,
Organizations, Repositories, Packages, Actions, Config, Notices,
Monitor, ...) — click `Actions` there for the runners view.
3. Repo: `Settings → Actions → Runners → Create new runner`, copy the 3. Repo: `Settings → Actions → Runners → Create new runner`, copy the
registration token. registration token. **This token is unrelated to `FORGEJO_TOKEN` in step
5 below** — easy to mix up since both are "a Forgejo token," but they're
different things from different pages: this one is single-purpose,
scoped to registering exactly one runner, generated on this
`Actions → Runners` page. `FORGEJO_TOKEN` (step 5) is a personal access
token from `Settings → Applications` on your own account, scoped to
`package:write`, used by CI to push images — it has nothing to do with
runner registration. If you paste `FORGEJO_TOKEN` into step 4 below by
mistake, registration fails with `invalid_argument: runner registration
token not found`.
4. Register and run the runner as a rootless Podman container, pointed at 4. Register and run the runner as a rootless Podman container, pointed at
the Podman socket from step 1 instead of docker.sock: the Podman socket from step 1 instead of docker.sock. This is two
separate commands, not one — `forgejo-runner register` is a one-shot
action that talks to Forgejo once and exits; the thing that actually
stays running and picks up jobs is a separate `forgejo-runner daemon`
process. Running only `register` under `--restart unless-stopped` (an
easy mistake, since it looks like a normal long-running container
command) makes it silently loop: register succeeds, the container exits,
Podman restarts it, it registers again, forever — never once actually
listening for a job. Both commands also need `--userns=keep-id`:
rootless Podman's socket file is owned by `k8s`'s own UID on the host,
but a container's "root" user normally maps to a *different*,
subuid-remapped UID under the hood — `--userns=keep-id` makes the
container's user *be* `k8s`'s actual UID instead, so it can open a
socket file owned by that UID. Without it, the daemon fails with
`permission denied` connecting to the socket.
```sh ```sh
# still as k8s # still as k8s
podman volume create forgejo-runner-data podman volume create forgejo-runner-data
podman run -d --name forgejo-runner --restart unless-stopped \
-e DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock" \ # one-shot: register, then exits (--rm, not -d)
-v "$XDG_RUNTIME_DIR/podman/podman.sock:$XDG_RUNTIME_DIR/podman/podman.sock" \ podman run --rm --userns=keep-id \
-v forgejo-runner-data:/data \ -v forgejo-runner-data:/data \
code.forgejo.org/forgejo/runner:6 \ code.forgejo.org/forgejo/runner:6 \
forgejo-runner register --no-interactive \ forgejo-runner register --no-interactive \
--instance https://git.boglabob.com \ --instance https://git.boglabob.com \
--token <TOKEN_FROM_STEP_3> --labels docker:docker://node:20-bookworm --token <TOKEN_FROM_STEP_3> --labels docker:docker://node:20-bookworm
# persistent: the actual daemon that listens for jobs
podman run -d --name forgejo-runner --restart unless-stopped \
--userns=keep-id \
-e DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman/podman.sock" \
-v "$XDG_RUNTIME_DIR/podman/podman.sock:$XDG_RUNTIME_DIR/podman/podman.sock" \
-v forgejo-runner-data:/data \
code.forgejo.org/forgejo/runner:6 \
forgejo-runner daemon
```
Confirm it's actually stable rather than looping — `podman ps --filter
name=forgejo-runner` should show one steadily increasing uptime, not a
container repeatedly restarting seconds after creation:
```sh
podman ps --filter name=forgejo-runner
podman logs --tail 20 forgejo-runner
``` ```
The registered runner picks up both workflows in `.forgejo/workflows/` The registered runner picks up both workflows in `.forgejo/workflows/`
`terraform.yml`'s `container:` image (stage 4) and `terraform.yml`'s `container:` image (stage 4) and
@ -325,12 +370,19 @@ doesn't share a blast radius with the cluster.
that same rootless Podman socket. that same rootless Podman socket.
5. Repo `Settings → Secrets and Variables → Actions`, add: 5. Repo `Settings → Secrets and Variables → Actions`, add:
- Secret `FORGEJO_TOKEN` — a personal access token (`Settings → Applications` - Secret `FORGEJO_TOKEN` — a personal access token (`Settings → Applications`
on your Forgejo user, scope `package:write`) used to push images. on your Forgejo user, scope `package:write`) used to push images. See
the callout on step 3 above — this is a different token from the
runner registration one, despite both living under "Forgejo tokens."
- Variable `FORGEJO_USER`, `FORGEJO_ORG` — your Forgejo username/org. - Variable `FORGEJO_USER`, `FORGEJO_ORG` — your Forgejo username/org.
If the `hello-app` package ends up private (Forgejo package visibility If the `hello-app` package ends up private (Forgejo package visibility
follows repo visibility by default), create the cluster-side pull secret follows repo visibility by default), create the cluster-side pull secret
and uncomment the `imagePullSecrets` line in `apps/hello-app/deployment.yaml`: and uncomment the `imagePullSecrets` line in `apps/hello-app/deployment.yaml`.
`<FORGEJO_USER>`/`<FORGEJO_TOKEN>` below are placeholders to replace with
your actual values, not literal syntax — bash reads a bare `<word>` as
input redirection, so pasting them unreplaced fails with a confusing
`syntax error near unexpected token 'newline''` instead of a helpful
message:
```sh ```sh
kubectl -n hello-app create secret docker-registry forgejo-registry \ kubectl -n hello-app create secret docker-registry forgejo-registry \