How to deploy on Linux with Docker
On Linux, elastic-fruit-runner runs inside a container and spawns ephemeral runner containers on the host’s Docker engine via a mounted socket.
Docker Compose with config file
Section titled “Docker Compose with config file”Create a config.yaml (see configuration reference):
orgs: - org: your-org auth: pat_token: ghp_xxx runner_group: Default runner_sets: # Linux arm64 runners - name: efr-linux-arm64 backend: docker image: ghcr.io/actions-runner-controller/actions-runner-controller/actions-runner-dind:latest labels: [self-hosted, linux, arm64] max_runners: 4 platform: linux/arm64
# Linux amd64 runners (Rosetta 2 emulation on Apple Silicon) - name: efr-linux-amd64 backend: docker image: ghcr.io/actions-runner-controller/actions-runner-controller/actions-runner-dind:latest labels: [self-hosted, linux, amd64] max_runners: 4 platform: linux/amd64
idle_timeout: 15mservices: elastic-fruit-runner: image: ghcr.io/boring-design/elastic-fruit-runner:latest restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - ./config.yaml:/etc/elastic-fruit-runner/config.yaml:rodocker compose up -dDocker Compose with GitHub App auth
Section titled “Docker Compose with GitHub App auth”orgs: - org: your-org auth: github_app: client_id: Iv1.xxxxxxxxxxxxxxxx installation_id: 12345678 private_key_path: /etc/efr/private-key.pem runner_group: Default runner_sets: # Linux arm64 runners - name: efr-linux-arm64 backend: docker image: ghcr.io/actions-runner-controller/actions-runner-controller/actions-runner-dind:latest labels: [self-hosted, linux, arm64] max_runners: 4 platform: linux/arm64
# Linux amd64 runners (Rosetta 2 emulation on Apple Silicon) - name: efr-linux-amd64 backend: docker image: ghcr.io/actions-runner-controller/actions-runner-controller/actions-runner-dind:latest labels: [self-hosted, linux, amd64] max_runners: 4 platform: linux/amd64
idle_timeout: 15mservices: elastic-fruit-runner: image: ghcr.io/boring-design/elastic-fruit-runner:latest restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock - ./config.yaml:/etc/elastic-fruit-runner/config.yaml:ro - ./private-key.pem:/etc/efr/private-key.pem:roHow it works
Section titled “How it works”Host Docker Engine├── elastic-fruit-runner container (long-running daemon)│ └── polls GitHub Scale Set API for jobs├── efr-linux-arm64-xxx container (ephemeral, one per job)├── efr-linux-amd64-xxx container (ephemeral, one per job)└── ...The daemon container mounts the host’s Docker socket (/var/run/docker.sock). When a job arrives, it creates a sibling container (not nested) on the host engine. Each runner container is destroyed after the job completes.
View logs
Section titled “View logs”docker logs -f elastic-fruit-runner
# With docker composedocker compose logs -f elastic-fruit-runner
# Filter errors with jq (logs are JSON)docker logs elastic-fruit-runner 2>&1 | jq 'select(.level == "ERROR")'Update
Section titled “Update”docker pull ghcr.io/boring-design/elastic-fruit-runner:latestdocker compose up -dsystemd integration (optional)
Section titled “systemd integration (optional)”If you prefer systemd to manage the container lifecycle:
[Unit]Description=Elastic Fruit RunnerAfter=docker.serviceRequires=docker.service
[Service]Restart=alwaysExecStartPre=-/usr/bin/docker rm -f elastic-fruit-runnerExecStart=/usr/bin/docker run --rm --name elastic-fruit-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /etc/elastic-fruit-runner/config.yaml:/etc/elastic-fruit-runner/config.yaml:ro \ ghcr.io/boring-design/elastic-fruit-runner:latestExecStop=/usr/bin/docker stop elastic-fruit-runner
[Install]WantedBy=multi-user.targetsudo systemctl enable --now elastic-fruit-runnersudo journalctl -fu elastic-fruit-runner