Files
my-cd-webhook/ai-context/infrastructure/rootless-docker-gitea-runner.md
fisher 3a6fafb5c7 Generic host/repo/branch-aware CD on adnanh/webhook
Replaces the per-project deploy scripts and self-contained webhook
receivers with one manifest-driven implementation that lives outside the
application repositories and can be updated independently of them.

First targets: domaindingo test and prod on s5.
2026-08-23 07:49:52 +00:00

3.6 KiB

Rootless Docker Gitea Runner Notes

Reusable setup for running Gitea Actions jobs on a rootless Docker host when jobs need Docker access (Playwright, Buildx). The runner runs as a container; job containers reach the host's rootless socket. Substitute the rootless socket path /run/user/<UID>/docker.sock for your runner user (examples use 3100).

Runner compose

Mount the rootless socket into the runner container:

services:
  gitea-runner-1:
    image: gitea/act_runner:latest
    container_name: s4-runner-1
    restart: unless-stopped
    environment:
      GITEA_INSTANCE_URL: https://gitea.example.com
      GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN}
      GITEA_RUNNER_NAME: s4-runner-1
      CONFIG_FILE: /data/config.yaml
    volumes:
      - runner1_data:/data
      - ./config.yaml:/data/config.yaml:ro
      - /run/user/3100/docker.sock:/var/run/docker.sock
volumes:
  runner1_data:

Runner config

container:
  docker_host: "-"                                                  # critical
  options: "-v /run/user/3100/docker.sock:/var/run/docker.sock"
  valid_volumes:
    - /run/user/3100/docker.sock                                    # source path only

docker_host: "-" stops act_runner from adding its own socket mount on top of the one in options, which otherwise fails job creation with Duplicate mount point: /var/run/docker.sock. Keep valid_volumes as the host source path only (not the src:dst bind form).

Workflow patterns

  • Buildx: use docker/setup-buildx-action@v3 with driver: docker. The default driver starts a separate BuildKit container that misbehaves on this runner shape; the docker driver uses the mounted daemon directly.
  • No setup-node cache: drop cache: pnpm from actions/setup-node@v4; the job network often can't reach the Gitea Actions cache service (minutes of restore/save timeouts). Use pnpm install --frozen-lockfile instead. Revisit only once the cache-service network path is confirmed.
  • Playwright: split browser E2E from validation — build + upload artifact in a normal job, then run Playwright in the official image (mcr.microsoft.com/playwright:v1.58.2-noble) against the downloaded artifact.

Host checks

docker context show; echo "$DOCKER_HOST"; ls -l /run/user/3100/docker.sock; docker info
# DOCKER_HOST should be unix:///run/user/3100/docker.sock
docker run --rm -v /run/user/3100/docker.sock:/var/run/docker.sock docker:27-cli docker version

If that container can't use the socket, fix rootless Docker before touching the runner.

Troubleshooting

  • Duplicate mount point: /var/run/docker.sock — set docker_host: "-", keep the bind only in options, valid_volumes = source path only, recreate.
  • WARNING: IPv4 forwarding is disabled may persist even after host net.ipv4.ip_forward=1. systemctl --user restart docker and re-check docker info. If jobs create containers and reach their networks, treat it as stale output, not a failure.
  • Buildx/build fails — use driver: docker; confirm docker version works through the mounted socket.

Useful commands

docker ps --format '{{.ID}} {{.Image}} {{.Status}} {{.Names}}'
docker logs --tail 120 s4-runner-1
docker compose up -d --force-recreate gitea-runner-1
tea actions runs --repo owner/repo
tea actions runs logs <run-id> --job <job-id> --repo owner/repo

Known-good (Grindex / current runner)

Host s4.fisher.hu; container s4-runner-1; image gitea/act_runner:latest; socket /run/user/3100/docker.sock; workflows in .gitea/workflows; Buildx driver: docker; setup-node cache disabled.