diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index b5ec95030ab..d8c6fa1333d 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -318,6 +318,7 @@ export default defineConfig({ { label: 'Upgrading Workflows', link: '/guides/upgrading/' }, { label: 'Using MCPs', link: '/guides/mcps/' }, { label: 'Network Configuration', link: '/guides/network-configuration/' }, + { label: 'ARC DinD for Copilot Coding Agent', link: '/guides/arc-dind-copilot-agent/' }, { label: 'OpenTelemetry', link: '/guides/open-telemetry/' }, { label: 'GitHub Actions Primer', link: '/guides/github-actions-primer/' }, { label: 'Using at Scale in Organizations', link: '/guides/using-at-scale/' }, diff --git a/docs/src/content/docs/guides/arc-dind-copilot-agent.md b/docs/src/content/docs/guides/arc-dind-copilot-agent.md new file mode 100644 index 00000000000..f733a35d522 --- /dev/null +++ b/docs/src/content/docs/guides/arc-dind-copilot-agent.md @@ -0,0 +1,184 @@ +--- +title: How to run GitHub Copilot coding agent on ARC with Docker-in-Docker +description: Configure Actions Runner Controller with Docker-in-Docker so GitHub Copilot coding agent can run on self-hosted Kubernetes runners. +sidebar: + order: 440 +--- + +Use this guide to run GitHub Copilot coding agent on an [Actions Runner Controller (ARC)](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/about-actions-runner-controller) runner scale set with Docker-in-Docker (DinD). + +## Prerequisites + +Before starting, confirm you have a Kubernetes cluster, `helm` and `kubectl` installed, and credentials for runner registration (a GitHub PAT or GitHub App credentials). + +> [!IMPORTANT] +> DinD (`containerMode.type="dind"`) is required for GitHub Copilot coding agent on ARC. Kubernetes mode (`containerMode.type="kubernetes"`) is not supported for this setup. + +## 1. Install the ARC controller + +```bash +helm install arc \ + --namespace "arc-system" --create-namespace \ + oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller +``` + +## 2. Create the runner namespace and auth secret + +Create the namespace and a Kubernetes secret with your runner registration credentials. You can use either a GitHub PAT or GitHub App credentials: + +```bash +kubectl create ns arc-runners + +# Option A: Personal access token +kubectl create secret generic arc-runner-secret \ + --namespace=arc-runners \ + --from-literal=github_token= + +# Option B: GitHub App (recommended for production) +kubectl create secret generic arc-runner-secret \ + --namespace=arc-runners \ + --from-literal=github_app_id= \ + --from-literal=github_app_installation_id= \ + --from-literal=github_app_private_key= +``` + +See [Authenticating to the GitHub API](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/authenticating-to-the-github-api) for details on each option. + +## 3. Install a runner scale set in DinD mode + +```bash +helm install "arc-runner-set" \ + --namespace "arc-runners" --create-namespace \ + --set githubConfigUrl="https://github.com//" \ + --set githubConfigSecret="arc-runner-secret" \ + --set containerMode.type="dind" \ + --set-json 'template.spec.containers=[{ + "name": "runner", + "image": "ghcr.io/actions/actions-runner:latest", + "command": ["/home/runner/run.sh"], + "securityContext": { + "capabilities": { + "add": ["NET_ADMIN"] + } + } + }]' \ + oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set +``` + +`NET_ADMIN` is required on the **runner container** so AWF can apply host-level `iptables` rules to the `DOCKER-USER` chain for egress filtering. + +When `containerMode.type="dind"` is enabled, ARC configures the DinD sidecar in privileged mode by default so the Docker daemon can run. If you use a custom pod template, ensure you do not remove that privileged setting. + +## 4. Verify the runner is online + +Open `https://github.com///settings/actions/runners` (or the organization-level runners page) and confirm the `arc-runner-set` runner is online. + +## 5. Target the runner set from a workflow + +Set your workflow frontmatter to use the runner scale set label and ARC DinD topology: + +```aw +--- +on: issues +runs-on: arc-runner-set +runner: + topology: arc-dind +--- +``` + +`runner.topology: arc-dind` is required so compiled workflows enable ARC DinD split-filesystem handling (a shared runner/daemon workspace root, Docker-daemon-visible mount paths, and ARC-specific sandbox setup). No other sandbox or network settings are needed — the defaults handle everything else. + +After editing the frontmatter, recompile the lock file: + +```bash +gh aw compile +``` + +Commit both the `.md` workflow file and the generated `.lock.yml` file. + +## 6. How it works + +When compiled workflows detect a `tcp://` value in `DOCKER_HOST` (set automatically by ARC DinD), a runtime probe activates ARC DinD handling: + +- **Sysroot staging** — system binaries (`/usr`, `/lib`, `/bin`, `/sbin`) are copied into a Docker named volume so the Docker daemon can provide them to the agent container without bind-mounting the runner's filesystem. +- **Workspace mount** — the checked-out repository at `GITHUB_WORKSPACE` is explicitly mounted into the agent container. Both runner and daemon can see it because ARC DinD shares the `/home/runner/_work/` volume. +- **Chroot identity** — the runner's UID/GID and home directory are patched into the AWF config so the agent runs with the correct identity inside the chroot. +- **Artifact consolidation** — agent output files are consolidated under `${{ runner.temp }}/gh-aw/` before upload so downstream jobs (detection, safe-outputs) can find them. + +## 7. Required versions + +Use versions at or above these minimums: + +| Component | Minimum version | Why | +| --- | --- | --- | +| `gh-aw` | `v0.82.5` | Includes ARC DinD workspace and detection fixes. | +| AWF (`agentic-workflow-firewall`) | `v0.27.22` | Includes DinD squid log permission fixes. | + +## Required and optional configuration + +| Item | Required? | Notes | +| --- | --- | --- | +| DinD container mode | **Yes** | GitHub Copilot coding agent needs a Docker daemon in the runner pod. | +| `NET_ADMIN` capability | **Yes** | Required on the runner container so AWF can manage host-level `DOCKER-USER` `iptables` rules. | +| `ghcr.io/actions/actions-runner:latest` | Recommended | Use the official runner image, or a compatible custom image with equivalent runner requirements. | +| Runner user | **Yes** | Non-root runner users are supported, but `sudo` must remain available on the runner host for AWF setup operations. | +| DinD sidecar privilege | **Yes** | ARC DinD mode configures a privileged sidecar for Docker daemon operation. | +| Shared work volume (`/home/runner/_work`) | **Yes** | Runner and Docker daemon share this volume in ARC DinD mode, so workspace mounts work without host path translation. | +| Specific Kubernetes distribution | **No** | Any conformant cluster works (for example minikube, EKS, AKS, or GKE). | +| Specific namespace names | **No** | `arc-system` and `arc-runners` are conventions only. | + +## Upgrading from manual workarounds + +If you previously used custom bootstrap actions, copilot shims, `/etc` pre-seeding, XDG environment overrides, or manual `DOCKER_HOST` / `MCP_GATEWAY_DOMAIN` settings to run on ARC DinD, remove them when adopting `runner.topology: arc-dind`. The compiler now handles all of these automatically. Leftover workarounds may conflict with the generated workflow steps. + +To migrate: + +1. Remove any `pre-agent-steps`, `resources`, or `safe-outputs.threat-detection.steps` blocks that were workarounds for ARC DinD. +2. Remove manual `engine.env` overrides for `XDG_CACHE_HOME`, `XDG_CONFIG_HOME`, `XDG_STATE_HOME`, `MCP_GATEWAY_DOMAIN`, `MCP_GATEWAY_PORT`, and `DOCKER_HOST`. +3. Remove `sandbox.agent.mounts` entries that staged files for the DinD daemon. +4. Add `runner.topology: arc-dind` to frontmatter. +5. Run `gh aw compile` and commit the updated lock file. + +## Known limitations + +- **`allowPrivilegeEscalation: false` is not supported.** The Copilot CLI install script uses `sudo`. Clusters that enforce `no-new-privileges` via PodSecurity Admission or OPA policies will fail at the install step. +- **MCP gateway Docker socket access** — on runners where `DOCKER_HOST` is a TCP endpoint and no Unix socket exists at `/var/run/docker.sock`, the MCP gateway may fail to connect to the Docker daemon (`Docker daemon is not accessible`). As a workaround, expose the DinD sidecar's Unix socket on the runner container at `/var/run/docker.sock` via a shared volume or symlink. See [#44251](https://github.com/github/gh-aw/issues/44251) for tracking. + +## Troubleshooting + +### Agent reports empty workspace + +The agent sees no files and exits with a no-op message. This was fixed in gh-aw v0.82.5. Upgrade and recompile: + +```bash +gh aw upgrade +gh aw compile +``` + +### Detection job fails with `spawn /usr/local/bin/copilot ENOENT` + +The threat-detection job can't find the Copilot binary. This was fixed in gh-aw v0.82.5 ([#44445](https://github.com/github/gh-aw/pull/44445)). The fix is the same — upgrade and recompile. + +### `sudo: The "no new privileges" flag is set` + +The runner pod's security context has `allowPrivilegeEscalation: false`. Remove that constraint or adjust your PodSecurity policy to allow privilege escalation in the runner container. + +### `Docker daemon is not accessible` in MCP gateway + +The MCP gateway can't reach the Docker socket. Ensure a Unix socket is available at `/var/run/docker.sock` on the runner container. For DinD setups where the daemon only exposes a TCP endpoint, share the sidecar's socket file via a volume: + +```yaml +# In your custom runner pod template +volumes: + - name: dind-sock + emptyDir: {} +# Mount in both runner and DinD sidecar containers +volumeMounts: + - name: dind-sock + mountPath: /var/run +``` + +## Related documentation + +- [Self-Hosted Runners](/gh-aw/reference/self-hosted-runners/) +- [ARC Helm charts](https://github.com/actions/actions-runner-controller/tree/master/charts) diff --git a/docs/src/content/docs/reference/self-hosted-runners.md b/docs/src/content/docs/reference/self-hosted-runners.md index e3658f498f6..63d9c5b030a 100644 --- a/docs/src/content/docs/reference/self-hosted-runners.md +++ b/docs/src/content/docs/reference/self-hosted-runners.md @@ -19,11 +19,15 @@ For these reasons, a non-sudo mode is not supported, including ARC configuration ## ARC with Docker-in-Docker (DinD) -Actions Runner Controller (ARC) deployments that use a Docker-in-Docker sidecar split the runner container and the Docker daemon container across separate filesystems, so bind mounts constructed from the runner's perspective fail inside the daemon. +For a complete ARC DinD setup walkthrough for GitHub Copilot coding agent, see [How to run GitHub Copilot coding agent on ARC with Docker-in-Docker](/gh-aw/guides/arc-dind-copilot-agent/). -`gh aw compile` emits a runtime probe in generated workflows that inspects `DOCKER_HOST` and appends `--docker-host-path-prefix /tmp/gh-aw` to the AWF invocation when the value matches `tcp://localhost:` or `tcp://127.0.0.1:`. No workflow-level configuration is required. +Actions Runner Controller (ARC) deployments that use a Docker-in-Docker sidecar split the runner container and the Docker daemon container across separate filesystems. -The probe is gated on AWF `v0.25.43` or newer. Workflows pinned to an older AWF version, or running on GitHub-hosted runners (where `DOCKER_HOST` is unset or points at a Unix socket), are unaffected. +Set `runner.topology: arc-dind` in workflow frontmatter for this environment. +Compiled workflows emit a runtime probe that inspects `DOCKER_HOST`. +Any `tcp://` endpoint (for example `tcp://localhost:2375`, `tcp://dind:2375`, or `tcp://172.30.0.5:2375`) is treated as ARC DinD, so ensure `DOCKER_HOST` points to the DinD daemon for that runner pod. + +With ARC DinD handling enabled, AWF receives `--docker-host`, shared-work sysroot staging is applied, and chroot config patching is enabled. The runtime no longer uses `--docker-host-path-prefix`. ## runs-on formats @@ -171,8 +175,8 @@ A working Docker daemon is required. The MCP gateway and sandbox run as containe ### Filesystem -- **Use `RUNNER_TEMP` for transient state.** Put sandbox state, tool downloads, and intermediate outputs in `$RUNNER_TEMP`, which is cleaned between jobs. On shared runners, avoid writing arbitrary workflow data to `/tmp` because it can persist across jobs. The `/tmp/gh-aw` prefix is reserved for gh-aw/AWF ARC DinD path rewriting. `actions/setup` resets `/tmp/gh-aw` at job start, and your normal runner `/tmp` cleanup policy should handle stale data from interrupted jobs. -- **No root or sudo assumption.** The runner user may not have root or `sudo` access (except for the initial iptables setup, which requires `sudo`). Tool installs, file operations, and sandbox setup should work as the unprivileged runner user. +- **Use `RUNNER_TEMP` for transient state.** Put sandbox state, tool downloads, and intermediate outputs in `$RUNNER_TEMP`, which is cleaned between jobs. On shared runners, avoid writing arbitrary workflow data to `/tmp` because it can persist across jobs. +- **No root assumption.** Tool installs, file operations, and sandbox setup should run as the unprivileged runner user, but host-level AWF setup requires `sudo` support on the runner host. - **No global installs.** Do not install packages to `/usr/local/`, `/opt/hostedtoolcache/`, or other system-wide paths. These may be read-only, shared across runners, or bind-mounted read-only inside the sandbox. Use job-scoped writable locations instead. - **No hardcoded `HOME` paths.** The runner's home directory may not be `/home/runner`. Use `$HOME` or `$RUNNER_TEMP` instead of hardcoded paths.