diff --git a/gitea/cache-server-config.yaml b/gitea/cache-server-config.yaml new file mode 100644 index 0000000..c2050f9 --- /dev/null +++ b/gitea/cache-server-config.yaml @@ -0,0 +1,5 @@ +cache: + # Path to the shared secret file (generated on the VPS directly, outside + # git - see /root/stacks/.data/gitea/cache_secret). Must match + # external_secret_file in runner-config.yaml exactly. + external_secret_file: "/data/cache_secret" diff --git a/gitea/compose.yml b/gitea/compose.yml index 83880bf..1861cb6 100644 --- a/gitea/compose.yml +++ b/gitea/compose.yml @@ -74,10 +74,40 @@ services: GITEA_RUNNER_NAME: docker-runner GITEA_RUNNER_LABELS: ubuntu-latest:docker://catthehacker/ubuntu:act-latest,ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04,ubuntu-20.04:docker://catthehacker/ubuntu:act-20.04 DOCKER_HOST: unix:///var/run/docker.sock + # Lets this container itself resolve host.docker.internal too (used by + # cache.external_server in runner-config.yaml) - the daemon needs this + # for its own pre-registration calls to runner-cache-server, separately + # from job containers (which get it via container.options's --add-host). + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ../.data/gitea/runner:/data - /var/run/docker.sock:/var/run/docker.sock - ./runner-config.yaml:/data/config.yaml:ro + - ../.data/gitea/cache_secret:/data/cache_secret:ro + restart: always + networks: + - compose_network + runner-cache-server: + image: gitea/act_runner:latest + container_name: gitea_runner_cache + command: ["act_runner", "cache-server", "--config", "/data/config.yaml", "--host", "0.0.0.0", "--port", "8088", "--dir", "/data/cache"] + environment: + TZ: ${TIMEZONE:-Europe/Amsterdam} + ports: + # Published so job containers - isolated on their own per-task Docker + # network, unreachable via container name regardless of network + # settings we tried - can still reach it via host.docker.internal, + # which resolves to their own network's gateway and routes back to + # this published port. Exposed on the VPS's public interface too; + # requests without a valid job's bearer token are rejected, but + # consider a firewall rule restricting this to Docker's private + # bridge ranges (172.16.0.0/12) if that's a concern. + - "8088:8088" + volumes: + - ../.data/gitea/runner-cache:/data/cache + - ./cache-server-config.yaml:/data/config.yaml:ro + - ../.data/gitea/cache_secret:/data/cache_secret:ro restart: always networks: - compose_network diff --git a/gitea/runner-config.yaml b/gitea/runner-config.yaml index c2bb35c..891c2e1 100644 --- a/gitea/runner-config.yaml +++ b/gitea/runner-config.yaml @@ -15,23 +15,28 @@ runner: cache: enabled: true dir: "" - # Leave empty for auto-detection - it correctly finds gitea_runner's own - # address once job containers actually share a network with it (see - # container.network below; a custom network name didn't work, but Docker's - # real default "bridge" network does). host: "" port: 0 - external_server: "" + # Both the shared network approaches we tried (a custom network name, then + # Docker's real "bridge" network) failed to make job containers reachable + # from/to this daemon's own embedded cache server - its host/port config + # is also unreliable in this act_runner version (confirmed by others: a + # fixed port still gets silently ignored in favor of a random one, see + # https://codeberg.org/forgejo/docs/issues/996). Using a dedicated + # `cache-server` process instead (see runner-cache-server in compose.yml), + # whose --host/--port CLI flags are documented and confirmed to actually + # work, reached via host.docker.internal + a published fixed port (proven + # reachable end-to-end from an isolated per-task-style container). + external_server: "http://host.docker.internal:8088/" + external_secret_file: "/data/cache_secret" container: - # A custom network name (e.g. falcon_network) was silently ignored - job - # containers still got their own isolated per-task network regardless. - # "bridge" (Docker's real, always-present default network) is honored - # instead - gitea_runner joins it too (see compose.yml) so both sides can - # reach each other by container name/IP. - network: "falcon_network" + network: "" privileged: false - options: "-v /var/run/docker.sock:/var/run/docker.sock" + # --add-host is what makes host.docker.internal (used for + # cache.external_server above) resolve inside job containers on Linux - + # Docker only wires it up automatically on Docker Desktop (Mac/Windows). + options: "-v /var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway" workdir_parent: "" valid_volumes: [] docker_host: ""