From f8ae28601d8aa5fb5e9658290c87c006bc0bdd4e Mon Sep 17 00:00:00 2001 From: Emil Simeonov Date: Thu, 16 Jul 2026 17:34:01 +0200 Subject: [PATCH] fix: fetch rootless Docker scripts on Arch Linux Arch Linux's docker package does not ship the rootless setup scripts (dockerd-rootless-setuptool.sh, dockerd-rootless.sh) or rootlesskit, unlike Debian's docker-ce-rootless-extras. The role now fetches them from moby/moby contrib/ at a pinned ref and installs rootlesskit explicitly. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- AGENTS.md | 6 ++++++ ansible/roles/gitea_runner/defaults/main.yml | 10 ++++++++++ .../gitea_runner/tasks/rootless_docker.yml | 20 +++++++++++++++++++ docs/tech/architecture.md | 9 ++++++++- docs/tech/decision-log.md | 10 ++++++++++ docs/user/faq.md | 2 ++ docs/user/troubleshooting.md | 9 +++++++++ 7 files changed, 65 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index ef59e94..7a1d707 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -475,6 +475,12 @@ main.yml → systemd_check → user_setup → rootless_docker → install_runner - `main.yml` handles: prune, integration_test (NOT install_runner — avoids duplicates) - `systemctl --user` tasks must be guarded by `docker_rootless_setup` - Template creation tasks are NOT guarded by `docker_rootless_setup` (they only create files) +- On Arch Linux, `rootless_docker.yml` fetches the rootless setup scripts + (`dockerd-rootless-setuptool.sh`, `dockerd-rootless.sh`) from `moby/moby` `contrib/` + at a pinned ref (`gitea_runner_rootless_scripts_ref`) into `/usr/bin` and installs + `rootlesskit` — Arch's `docker` package ships neither. These fetch tasks run + regardless of `docker_rootless_setup` so CI exercises them on the archlinux platform. + See ADR-011 in the decision log. ## Molecule Scenarios diff --git a/ansible/roles/gitea_runner/defaults/main.yml b/ansible/roles/gitea_runner/defaults/main.yml index 5d7abea..87da8cd 100644 --- a/ansible/roles/gitea_runner/defaults/main.yml +++ b/ansible/roles/gitea_runner/defaults/main.yml @@ -54,6 +54,16 @@ gitea_runner_docker_apt_source_line: >- # Set to false in CI/molecule to skip rootless daemon startup (needs kernel userns) gitea_runner_docker_rootless_setup: true +# Rootless Docker helper scripts (dockerd-rootless-setuptool.sh / dockerd-rootless.sh). +# Arch Linux's "docker" package does not ship these (unlike Debian's docker-ce-rootless-extras), +# and no official Arch package provides them. They are fetched from the upstream moby/moby +# "contrib/" directory at the git ref below. The scripts are stable bash wrappers that are +# version-agnostic with respect to the dockerd binary, so a pinned ref is safe. +gitea_runner_rootless_scripts_ref: "v28.5.1" +# Install dir MUST match the location of the "docker" / "dockerd" / "rootlesskit" binaries so +# that dockerd-rootless-setuptool.sh (which derives BIN from its own dirname) finds them co-located. +gitea_runner_rootless_scripts_install_dir: "/usr/bin" + # Rootless Docker network driver: "pasta" (IPv6 support) or "slirp4netns" (IPv4 only) # pasta has proper outgoing IPv6 support; slirp4netns does not (known limitation). gitea_runner_docker_rootless_net_driver: "pasta" diff --git a/ansible/roles/gitea_runner/tasks/rootless_docker.yml b/ansible/roles/gitea_runner/tasks/rootless_docker.yml index 7ef4067..add87af 100644 --- a/ansible/roles/gitea_runner/tasks/rootless_docker.yml +++ b/ansible/roles/gitea_runner/tasks/rootless_docker.yml @@ -62,9 +62,29 @@ - passt - fuse-overlayfs - rsync + # rootlesskit is the userspace networking/namespace driver for rootless Docker. + # It is NOT a dependency of the "docker" package on Arch and must be installed explicitly. + - rootlesskit state: present when: ansible_facts['os_family'] == 'Archlinux' +# Arch Linux's "docker" package does not ship the rootless setup scripts (dockerd-rootless-setuptool.sh +# and dockerd-rootless.sh), unlike Debian/Ubuntu's docker-ce-rootless-extras. No official Arch package +# provides them, so fetch them from the upstream moby/moby contrib/ directory. They are installed +# alongside the docker binaries (/usr/bin) because dockerd-rootless-setuptool.sh derives its BIN +# directory from its own location and expects docker/dockerd/rootlesskit to be co-located there. +- name: Fetch rootless Docker setup scripts (Arch Linux) + ansible.builtin.get_url: + url: "https://raw.githubusercontent.com/moby/moby/{{ gitea_runner_rootless_scripts_ref }}/contrib/{{ item.name }}" + dest: "{{ gitea_runner_rootless_scripts_install_dir }}/{{ item.name }}" + mode: "0755" + owner: root + group: root + loop: + - name: dockerd-rootless-setuptool.sh + - name: dockerd-rootless.sh + when: ansible_facts['os_family'] == 'Archlinux' + - name: Check if rootless Docker is already set up ansible.builtin.stat: path: "{{ gitea_runner_home }}/.config/systemd/user/docker.service" diff --git a/docs/tech/architecture.md b/docs/tech/architecture.md index dd377d0..0762b8e 100644 --- a/docs/tech/architecture.md +++ b/docs/tech/architecture.md @@ -53,7 +53,7 @@ main.yml → systemd_check → user_setup → rootless_docker → install_runner | `main.yml` | Entry point — includes all other task files in order | | `systemd_check.yml` | Verifies systemd is available on the target host | | `user_setup.yml` | Creates the per-runner system user, enables lingering, configures subuid/subgid, creates data and config directories | -| `rootless_docker.yml` | Installs Docker packages (apt for Debian/Ubuntu, pacman for Arch), runs `dockerd-rootless-setuptool.sh install`, starts and enables the rootless Docker daemon | +| `rootless_docker.yml` | Installs Docker packages (apt for Debian/Ubuntu, pacman for Arch), provisions the rootless setup scripts on Arch (not shipped by the `docker` package), runs `dockerd-rootless-setuptool.sh install`, starts and enables the rootless Docker daemon | | `install_runner.yml` | Downloads the gitea_runner binary, creates the config file, validates the binary, registers the runner with Gitea, creates and starts the systemd user service | | `download_gitea_runner.yml` | Downloads the gitea_runner binary from GitHub releases | | `validate.yml` | Validates the downloaded binary | @@ -190,6 +190,13 @@ per-workaround DNS hacks. Containers launched by the runner never have root access to the host. The rootless Docker daemon is started as a systemd user service and persists via lingering. +#### Platform-specific rootless provisioning + +The rootless setup scripts (`dockerd-rootless-setuptool.sh` and `dockerd-rootless.sh`) are provided differently per OS: + +- **Debian/Ubuntu** — shipped by the `docker-ce-rootless-extras` package (installed via the Docker APT repo). +- **Arch Linux** — the `docker` package does **not** include these scripts, and no official Arch package provides them. The role fetches them from the upstream `moby/moby` `contrib/` directory at a pinned, overridable git ref (`gitea_runner_rootless_scripts_ref`, default `v28.5.1`) and installs them into `/usr/bin` — co-located with `docker`/`dockerd`/`rootlesskit`, which is required because `dockerd-rootless-setuptool.sh` derives its `BIN` directory from its own location and expects those binaries alongside it. The `rootlesskit` package (a required rootless runtime dependency that is not pulled in by Arch's `docker` package) is also installed explicitly. + ### Secret handling Registration tokens and admin API tokens are never exposed on the command line. The `RunnerManager._extra_vars_file()` context manager: diff --git a/docs/tech/decision-log.md b/docs/tech/decision-log.md index 45e4332..1fc99f7 100644 --- a/docs/tech/decision-log.md +++ b/docs/tech/decision-log.md @@ -121,3 +121,13 @@ Key technical decisions for the GRM project, extracted from `CHANGELOG.md` and ` **Rationale:** Hardcoding the number of CI runners would require manual updates when runners are added or removed. Dynamic discovery auto-detects repo/org-level runners via the API. For instance-level runners (which may not be visible without admin scope), it falls back to the `MOLECULE_RUNNERS` repo variable, then to a default of 3. The workflow automatically scales the matrix to match available runners, distributing test pairs evenly. **Source:** `AGENTS.md` (Dynamic Runner Discovery), `.gitea/workflows/ci.yml` (discover-runners step in the validate job) + +--- + +## ADR-011: Fetch Rootless Docker Scripts from moby/moby on Arch Linux + +**Date:** 2026-07-16 (v0.19.0) + +**Decision:** On Arch Linux, fetch the rootless Docker setup scripts (`dockerd-rootless-setuptool.sh` and `dockerd-rootless.sh`) from the upstream `moby/moby` `contrib/` directory at a pinned git ref (`gitea_runner_rootless_scripts_ref`, default `v28.5.1`) and install them into `/usr/bin`. Install the `rootlesskit` package explicitly. + +**Rationale:** Arch's `docker` package does not ship the rootless setup scripts (unlike Debian/Ubuntu's `docker-ce-rootless-extras`), and no official Arch package provides them (`pkgfile` confirms zero providers). `rootlesskit` — the required userspace networking/namespace driver — is also not a dependency of the `docker` package and must be installed explicitly. Without these, `grm install` fails with `No such file or directory: dockerd-rootless-setuptool.sh`. The scripts are installed into `/usr/bin` (not `/usr/local/bin`) because `dockerd-rootless-setuptool.sh` derives its `BIN` directory from its own location and expects `docker`, `dockerd`, and `rootlesskit` to be co-located. The scripts are stable, version-agnostic bash wrappers, so a pinned ref is safe across `dockerd` versions; the ref is overridable via `gitea_runner_rootless_scripts_ref`. This bug was not caught by CI because molecule scenarios run with `gitea_runner_docker_rootless_setup: false` (rootless daemon startup needs kernel userns unavailable in CI containers), so the Arch rootless path was never exercised — the script-fetch tasks now run regardless of that flag to provide URL-validation coverage. diff --git a/docs/user/faq.md b/docs/user/faq.md index 64494ee..c81cfff 100644 --- a/docs/user/faq.md +++ b/docs/user/faq.md @@ -105,6 +105,8 @@ grm remove prod-runner --force GRM supports Arch Linux (rolling), Ubuntu 22.04/24.04, and Debian 12. All supported OSes are tested in CI via Molecule scenarios on every PR that changes Ansible files. +On Arch Linux, the rootless Docker setup scripts (`dockerd-rootless-setuptool.sh`, `dockerd-rootless.sh`) and the `rootlesskit` runtime are provisioned automatically — Arch's `docker` package does not ship them. No extra setup is required. + ## How to change the UI language Set the `GRM_LANG` environment variable to one of the supported languages: `en` (English, default), `bg` (Bulgarian), `de` (German), `ru` (Russian), `zh` (Chinese), `pl` (Polish). diff --git a/docs/user/troubleshooting.md b/docs/user/troubleshooting.md index 22e80e9..576d3a6 100644 --- a/docs/user/troubleshooting.md +++ b/docs/user/troubleshooting.md @@ -2,6 +2,14 @@ ## Installation Issues +### `No such file or directory: dockerd-rootless-setuptool.sh` (Arch Linux) + +**Symptom:** `grm install` fails on an Arch Linux host during rootless Docker setup with `Error executing command: [Errno 2] No such file or directory: b'dockerd-rootless-setuptool.sh'`. + +**Cause:** Arch's `docker` package does not ship the rootless setup scripts (unlike Debian/Ubuntu's `docker-ce-rootless-extras`), and `rootlesskit` is not a dependency of the `docker` package. + +**Solution:** This is handled automatically by GRM ≥ v0.19.0. Ensure you are on the latest release (`git checkout $(git describe --tags --abbrev=0)`). The role fetches the scripts from upstream `moby/moby` and installs `rootlesskit` automatically. If it still fails, verify the host can reach `raw.githubusercontent.com` (the script source) and check the Ansible log under `~/.local/state/grm/logs/`. + ### Ansible connection fails (UNREACHABLE) **Symptom:** Ansible reports `UNREACHABLE` when trying to connect to the target host. @@ -179,6 +187,7 @@ If Docker is not installed, install it via your package manager or [Docker's off | Symptom | Likely Cause | Solution | |---------|-------------|----------| | Ansible UNREACHABLE | SSH connection failed | Verify `--user`, `--key`, and host reachability | +| `No such file ... dockerd-rootless-setuptool.sh` (Arch) | Arch `docker` pkg lacks rootless scripts + `rootlesskit` | Fixed in v0.19.0; update GRM to latest release | | `GITEA_URL must be set` | Missing environment variable | Set `GITEA_URL` in `.env` or pass `--url` | | `GITEA_REGISTRATION_TOKEN must be set` | Missing environment variable | Set `GITEA_REGISTRATION_TOKEN` in `.env` or pass `--token` | | Runner appears offline | Registration failed or service not running | Check GITEA_URL, token validity, and service status |