GRM-144: feat(runner): enable IPv6 in rootless Docker via pasta network driver
Post-merge / detect-type (push) Waiting to run
Post-merge / configure-repo (push) Waiting to run
Post-merge / release (push) Waiting to run
Post-merge / validate-commit-msg (push) Waiting to run
Post-merge / badges (push) Waiting to run
Post-merge / sync-wiki (push) Waiting to run
Post-merge / vikunja (push) Waiting to run
Post-merge / publish (push) Waiting to run
Post-merge / detect-type (push) Waiting to run
Post-merge / configure-repo (push) Waiting to run
Post-merge / release (push) Waiting to run
Post-merge / validate-commit-msg (push) Waiting to run
Post-merge / badges (push) Waiting to run
Post-merge / sync-wiki (push) Waiting to run
Post-merge / vikunja (push) Waiting to run
Post-merge / publish (push) Waiting to run
This commit was merged in pull request #214.
This commit is contained in:
@@ -57,7 +57,7 @@ CI also runs a best-effort `make workflow-dryrun` step (skipped if act_runner is
|
||||
## Architecture
|
||||
|
||||
- **Python CLI** (`src/grm/`) — Click-based CLI that delegates to Ansible
|
||||
- **Ansible Role** (`ansible/roles/gitea-runner/`) — Idempotent role for rootless Docker runner setup
|
||||
- **Ansible Role** (`ansible/roles/gitea-runner/`) — Idempotent role for rootless Docker runner setup with pasta networking (IPv6 support)
|
||||
- **devx package** (installed from git) — Reusable CI/CD tools: auto-merge, post-merge, release, publishing, molecule distribution, PR reviews, failure notifications
|
||||
- **Versioning** (`cliff.toml`) — git-cliff configuration for automated semver versioning from conventional commits
|
||||
|
||||
|
||||
@@ -53,3 +53,10 @@ docker_apt_source_line: >-
|
||||
{{ ansible_facts['distribution_release'] }} stable
|
||||
# Set to false in CI/molecule to skip rootless daemon startup (needs kernel userns)
|
||||
docker_rootless_setup: true
|
||||
|
||||
# Rootless Docker network driver: "pasta" (IPv6 support) or "slirp4netns" (IPv4 only)
|
||||
# pasta has proper outgoing IPv6 support; slirp4netns does not (known limitation).
|
||||
docker_rootless_net_driver: "pasta"
|
||||
|
||||
# IPv6 subnet for rootless Docker containers (ULA range, not routable on internet)
|
||||
docker_ipv6_cidr: "fd00:dead:beef::/48"
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
name:
|
||||
- uidmap
|
||||
- slirp4netns
|
||||
- passt
|
||||
- fuse-overlayfs
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
@@ -57,6 +58,7 @@
|
||||
- docker
|
||||
- docker-compose
|
||||
- slirp4netns
|
||||
- passt
|
||||
- fuse-overlayfs
|
||||
- rsync
|
||||
state: present
|
||||
@@ -106,12 +108,48 @@
|
||||
group: "{{ gitea_runner_service_user }}"
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Configure rootless Docker to disable IPv6
|
||||
- name: Ensure systemd user override directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ gitea_runner_home }}/.config/systemd/user/docker.service.d"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
owner: "{{ gitea_runner_service_user }}"
|
||||
group: "{{ gitea_runner_service_user }}"
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Configure rootless Docker to use pasta with IPv6
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ gitea_runner_home }}/.config/systemd/user/docker.service.d/override.conf"
|
||||
content: |
|
||||
[Service]
|
||||
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET={{ docker_rootless_net_driver }}"
|
||||
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=implicit"
|
||||
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--ipv6"
|
||||
mode: "0644"
|
||||
owner: "{{ gitea_runner_service_user }}"
|
||||
group: "{{ gitea_runner_service_user }}"
|
||||
register: docker_network_override
|
||||
when: docker_rootless_setup
|
||||
|
||||
- name: Reload systemd user daemon if network config changed
|
||||
ansible.builtin.command: systemctl --user daemon-reload
|
||||
become: true
|
||||
become_user: "{{ gitea_runner_service_user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ gitea_runner_uid }}"
|
||||
changed_when: true
|
||||
when:
|
||||
- docker_rootless_setup
|
||||
- docker_network_override is changed
|
||||
|
||||
- name: Configure rootless Docker daemon with IPv6 enabled
|
||||
ansible.builtin.copy:
|
||||
dest: "{{ gitea_runner_home }}/.config/docker/daemon.json"
|
||||
content: |
|
||||
{
|
||||
"ipv6": false
|
||||
"ipv6": true,
|
||||
"ip6tables": true,
|
||||
"fixed-cidr-v6": "{{ docker_ipv6_cidr }}"
|
||||
}
|
||||
mode: "0644"
|
||||
owner: "{{ gitea_runner_service_user }}"
|
||||
@@ -128,7 +166,7 @@
|
||||
changed_when: true
|
||||
when:
|
||||
- docker_rootless_setup
|
||||
- docker_ipv6_config is changed
|
||||
- docker_ipv6_config is changed or docker_network_override is changed
|
||||
|
||||
- name: Wait for rootless Docker daemon to be ready
|
||||
ansible.builtin.command: docker version
|
||||
|
||||
@@ -173,9 +173,21 @@ Each runner operates under a dedicated unprivileged system user. The Docker daem
|
||||
|
||||
- User namespace mapping via `/etc/subuid` and `/etc/subgid` (range: 100000-165535)
|
||||
- Rootless Docker socket at `/run/user/<UID>/docker.sock`
|
||||
- `slirp4netns` for user-mode networking
|
||||
- `pasta` for user-mode networking with IPv6 support (replaces `slirp4netns`, which lacks outgoing IPv6)
|
||||
- `fuse-overlayfs` for rootless container storage
|
||||
|
||||
The rootless Docker daemon is configured via a systemd user override
|
||||
(`docker.service.d/override.conf`) that sets:
|
||||
|
||||
- `DOCKERD_ROOTLESS_ROOTLESSKIT_NET=pasta` — use pasta as the network driver
|
||||
- `DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=implicit` — pasta's native port forwarding
|
||||
- `DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS=--ipv6` — enable IPv6 routing
|
||||
|
||||
The daemon.json enables IPv6 with a ULA subnet (`fd00:dead:beef::/48`)
|
||||
for container addressing. This ensures runner containers can reach
|
||||
both IPv4 and IPv6 services (e.g., the Gitea registry) without
|
||||
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.
|
||||
|
||||
### Secret handling
|
||||
|
||||
Reference in New Issue
Block a user