diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index ebd7f9e..4e18927 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -39,6 +39,7 @@ jobs: - android-runner - android-runner-host - org-runner + - no-docker-socket fail-fast: false max-parallel: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 74e79e4..5bca9e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [0.1.6] - 2026-08-20 +### Added +- `github_runner_mount_docker_socket` (default `true`): whether to mount the host's `/var/run/docker.sock` into the runner container. Set to `false` for runners whose CI jobs never use docker — it drops a root-equivalent privilege, and on a desktop host it guarantees the runner's jobs can't churn veth interfaces (each add/remove aborts in-flight Chrome requests on that host with `ERR_NETWORK_CHANGED`). +- `no-docker-socket` molecule scenario verifying the runner converges without the socket bind. + ## [0.1.5] - 2026-08-12 ### Fixed - The deploy no longer replaces a runner container while its runner is mid-job (which destroyed the CI job: GitHub waits out the runner heartbeat ~10 min, then fails every remaining step). When a replace is imminent — new image digest or config change — and the existing runner is busy, the role now polls the GitHub runners API until the runner is idle before replacing, failing the deploy loudly on timeout instead of killing the job. The busy-check fails loudly on a paginated (>100 runners) listing, treats malformed/rate-limited API responses as still-waiting, and clamps the poll interval to >=1s. diff --git a/README.md b/README.md index 489c11a..7a462fe 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ github_runner_env_file | whether to use an env file for pas github_runner_env_filename | the filename of the env file for passing extra environment variables into the container (defaults to ".env") github_runner_github_host | The GITHUB_HOST used for registering the runner (defaults to "github.com") github_runner_persist_config | whether to persist runner configuration across container restarts using a named volume (defaults to true) +github_runner_mount_docker_socket | whether to mount the host's /var/run/docker.sock into the runner container; set to false for runners whose jobs never use docker to drop the root-equivalent privilege (defaults to true) github_runner_stop_timeout | seconds docker waits after SIGTERM before SIGKILL when stopping the runner container, e.g. while replacing it on an image bump (defaults to 10) github_runner_docker_timeout | Docker API client timeout in seconds for the deploy task; stopping and removing a crash-looping runner can exceed the SDK's 60s default (defaults to 180) github_runner_drain_before_replace | when a deploy is about to replace the runner container while the runner is executing a CI job, wait for the job to finish instead of destroying it (defaults to true) diff --git a/galaxy.yml b/galaxy.yml index bcda969..3d657e4 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -8,7 +8,7 @@ description: "Installs github self hosted repo or org runners within a docker co can be a vanilla runner, or one with java / android installed." license_file: LICENSE readme: README.md -version: 0.1.5 +version: 0.1.6 repository: https://github.com/compscidr/ansible-github-runner tags: - github diff --git a/molecule/no-docker-socket/converge.yml b/molecule/no-docker-socket/converge.yml new file mode 100644 index 0000000..5b9c753 --- /dev/null +++ b/molecule/no-docker-socket/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + become: true + gather_facts: true + roles: + - role: github_runner diff --git a/molecule/no-docker-socket/molecule.yml b/molecule/no-docker-socket/molecule.yml new file mode 100644 index 0000000..b452299 --- /dev/null +++ b/molecule/no-docker-socket/molecule.yml @@ -0,0 +1,36 @@ +--- +dependency: + name: galaxy + options: + requirements-file: requirements.yml +driver: + name: docker +platforms: + - name: ubuntu-22.04-no-docker-socket + image: geerlingguy/docker-ubuntu2204-ansible:latest + command: "" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + privileged: true + pre_build_image: true +provisioner: + name: ansible + env: + ANSIBLE_ROLES_PATH: ${MOLECULE_PROJECT_DIRECTORY}/roles + playbooks: + prepare: ../default/prepare.yml + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + ubuntu-22.04-no-docker-socket: + github_runner_personal_access_token: "test-token-no-docker-socket" + github_runner_name: "test-runner-no-docker-socket" + github_runner_repo: "test/repo" + github_runner_labels: "self-hosted,jvm" + github_runner_java: true + github_runner_mount_docker_socket: false +verifier: + name: ansible diff --git a/molecule/no-docker-socket/verify.yml b/molecule/no-docker-socket/verify.yml new file mode 100644 index 0000000..1e86d0a --- /dev/null +++ b/molecule/no-docker-socket/verify.yml @@ -0,0 +1,37 @@ +--- +- name: Verify runner without docker socket + hosts: all + gather_facts: false + become: true + tasks: + - name: Check if GitHub runner container is running + community.docker.docker_container_info: + name: "{{ github_runner_name }}" + register: runner_container + + - name: Verify container exists + ansible.builtin.assert: + that: + - runner_container.exists + fail_msg: "GitHub runner container does not exist" + success_msg: "GitHub runner container exists" + + - name: Verify container is running + ansible.builtin.assert: + that: + - runner_container.container.State.Running + fail_msg: "GitHub runner container is not running" + success_msg: "GitHub runner container is running" + + - name: Debug HostConfig.Binds + ansible.builtin.debug: + var: runner_container.container.HostConfig.Binds + + - name: Verify docker socket is NOT mounted + ansible.builtin.assert: + that: + # default([], true) also covers Binds being None (e.g. every volume + # landing in Mounts instead): no binds at all still means no socket. + - runner_container.container.HostConfig.Binds | default([], true) | select('search', '/var/run/docker.sock') | list | length == 0 + fail_msg: "Docker socket should not be mounted with github_runner_mount_docker_socket: false" + success_msg: "Docker socket correctly not mounted" diff --git a/roles/github_runner/defaults/main.yml b/roles/github_runner/defaults/main.yml index 08034af..1cadb50 100644 --- a/roles/github_runner/defaults/main.yml +++ b/roles/github_runner/defaults/main.yml @@ -23,6 +23,14 @@ github_runner_adb_port: 5037 # adb client reach an adb server running on the host at 127.0.0.1:5037. github_runner_network_mode: default +# Whether to mount the host's /var/run/docker.sock into the runner container. +# Only needed when CI jobs themselves use docker (builds, testcontainers, +# service containers). Set to false for runners whose jobs never touch docker: +# it drops a root-equivalent privilege, and on a desktop host it guarantees the +# runner's jobs can't churn veth interfaces (each add/remove aborts in-flight +# Chrome requests on that host with ERR_NETWORK_CHANGED). +github_runner_mount_docker_socket: true + github_runner_github_host: "github.com" github_runner_persist_config: true diff --git a/roles/github_runner/vars/main.yml b/roles/github_runner/vars/main.yml index b5b55eb..1fc1630 100644 --- a/roles/github_runner/vars/main.yml +++ b/roles/github_runner/vars/main.yml @@ -13,7 +13,7 @@ github_runner_ports: >- }} github_runner_volumes: >- {{ - ['/var/run/docker.sock:/var/run/docker.sock'] + + (['/var/run/docker.sock:/var/run/docker.sock'] if github_runner_mount_docker_socket else []) + (['/root/.android:/root/.android'] if github_runner_android else []) + ([github_runner_name ~ '-runner-data:/runner-data'] if github_runner_persist_config else []) }}