Skip to content
GantryCD

Runner groups

A runner group starts a fresh runner for each run. Set one up with GitHub Actions or run one in your Kubernetes cluster.

GitHub Actions

GantryCD can dispatch a workflow in a GitHub repository. GitHub then provides the runner.

  1. Create a GitHub App with Actions: read and write repository access.
  2. Install the App on the repository that will hold the workflow.
  3. Expand the workflow template below and copy it to .github/workflows/gantrycd-runner.yaml in that repository.
  4. In GantryCD, open Runner groups → Create Runner Group and choose GitHub Actions.
  5. Enter:
    • the repository as owner/name;
    • the workflow file and ref;
    • the App ID and private key;
    • the maximum number of concurrent runs.
Workflow template
name: GantryCD Runner
run-name: gantrycd-${{ inputs.correlation-id }}

on:
  workflow_dispatch:
    inputs:
      assignment-token:
        required: true
      gantrycd-url:
        required: true
      correlation-id:
        required: true
      runner-version:
        required: true

env:
  TENV_VERSION: v4.12.2

jobs:
  run:
    # Change this label to choose another GitHub runner.
    runs-on: ubuntu-slim
    timeout-minutes: 75

    steps:
      - name: Resolve architecture and tool paths
        env:
          HOST_ARCH: ${{ runner.arch }}
        run: |
          set -euo pipefail
          case "${HOST_ARCH}" in
            X64)   arch=amd64; tenv_arch=x86_64 ;;
            ARM64) arch=arm64; tenv_arch=arm64  ;;
            *) echo "unsupported runner.arch: ${HOST_ARCH}" >&2; exit 1 ;;
          esac
          TOOLS_DIR="${HOME}/.cache/gantrycd-tools"
          mkdir -p "${TOOLS_DIR}/tenv"
          printf '%s\n' "${TOOLS_DIR}/tenv" >> "${GITHUB_PATH}"
          {
            echo "ARCH=${arch}"
            echo "TENV_ARCH=${tenv_arch}"
            echo "TOOLS_DIR=${TOOLS_DIR}"
            echo "TENV_ROOT=${HOME}/.tenv"
          } >> "${GITHUB_ENV}"

      - name: Install cosign
        run: |
          set -euo pipefail
          curl -fsSL -o cosign \
            "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-${ARCH}"
          sudo install -m 0755 cosign /usr/local/bin/cosign
          rm cosign

      - name: Download runner binary
        env:
          RUNNER_VERSION: ${{ inputs.runner-version }}
        run: |
          set -euo pipefail
          curl -fsSL -o runner.tar.gz \
            "https://artifacts.gantrycd.io/releases/${RUNNER_VERSION}/runner-${RUNNER_VERSION}-linux-${ARCH}.tar.gz"
          tar -xzf runner.tar.gz
          chmod +x runner

      - name: Cache the OpenTofu runtime
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
        with:
          path: |
            ~/.cache/gantrycd-tools/tenv
            ~/.tenv
          key: ${{ runner.os }}-${{ runner.arch }}-tofu-runtime-${{ env.TENV_VERSION }}-${{ github.run_id }}
          restore-keys: |
            ${{ runner.os }}-${{ runner.arch }}-tofu-runtime-${{ env.TENV_VERSION }}-

      - name: Install tenv
        run: |
          set -euo pipefail
          if [ -x "${TOOLS_DIR}/tenv/tenv" ]; then
            echo "tenv ${TENV_VERSION} restored from cache"
          else
            curl -fsSL "https://github.com/tofuutils/tenv/releases/download/${TENV_VERSION}/tenv_${TENV_VERSION}_Linux_${TENV_ARCH}.tar.gz" \
              | tar -xz -C "${TOOLS_DIR}/tenv"
          fi
          command -v tenv

      - name: Run the ephemeral runner
        env:
          BACKEND_URL: ${{ inputs.gantrycd-url }}
          EPHEMERAL_RUNNER_JWT: ${{ inputs.assignment-token }}
        run: ./runner

The template accepts the assignment from GantryCD, downloads the matching runner version, and starts it. Keep its four workflow inputs and its run-name unchanged.

GitHub Actions receives no runner spec overrides from a stack. The runner label (runs-on), container image, and other compute options are set in the workflow.

You can reuse the GitHub App from your repository integration. The App ID and private key still need to be added to the runner group.

Self-hosted with Helm

The runner group Helm chart runs a launcher in your cluster. The launcher creates one short-lived Kubernetes Pod for each run.

First, open Runner groups → Create Runner Group, choose Self-hosted, and save the group ID and private key. The private key is shown only once.

Create a namespace and store the key:

kubectl create namespace acme
kubectl -n acme create secret generic acme-runners-key \
  --from-file=private-key=/path/to/private-key.pem

Install one runner group in that namespace:

helm install acme-runners \
  oci://ghcr.io/gantrycd/helm/gantrycd-runner-group-kubernetes \
  --version vX.Y.Z \
  --namespace acme \
  --set groupID=<group-id> \
  --set backendURL=http://gantrycd.gantrycd.svc:8080 \
  --set privateKey.existingSecret=acme-runners-key

Use a values file for shared settings:

maxConcurrent: 4

ephemeralRunner:
  serviceAccount: gantrycd-runner
  serviceAccountCreate: true
  cpu: "1"
  memory: 1Gi

cpu and memory set both the request and limit for every runner Pod. A stack can override each value separately.

The backend URL must be reachable from the cluster. The service account is the identity used by the short-lived runner Pods, so attach the cloud access they need to it.

View all chart values for your version:

helm show values \
  oci://ghcr.io/gantrycd/helm/gantrycd-runner-group-kubernetes \
  --version vX.Y.Z

Use runner group selectors to route stacks and pass runner spec overrides supported by the selected group.