Ga naar inhoud

Docker runner hosten

Wat is een runner?

Voor developer gebruik is het toepasselijk om (in het geval van GitHub) een actionsrunner te gebruiken. In deze runner worden .yml files gedraaid die getriggerd worden door acties op geselecteerde branches.

Bij GitHub kun je runners huren. Deze runners worden aan de eind van de maand in kosten gebracht en verschillen tussen per model. De kosten zijn voor de gebruikte minuten van runner. Oftewel als er geen workflow draaiende is, worden er geen kosten in kaart gebracht.

Voor runners worden er voor publieke repositories geen kosten in kaart gebracht, zodat de GitHub community beschikbaar wordt voor publieke doeleindes.

GitHub heeft abonementen, waardoor de kosten van runners minder worden. Er zijn drie verschillende soorten abonnementen waar gebruik gemaakt van kunnen worden. Deze gratis minuten gelden voor de self-hosted runners of de ‘gratis’ runners van GitHub.

Item Free Team Enterpise
Kosten $0 USD per user/month $4 USD per user/month $21 USD per user/month
GitHub Actions 2,000 minutes/month (Free for public repositories) 3,000 minutes/month (Free for public repositories) 50,000 minutes/month (Free for public repositories)

Kosten runners

Linux

Hardware Core size Prijs / minuut
x64 1 $0.002
x64 2 $0.006
x64 4 $0.012
x64 8 $0.022
x64 16 $0.042
x64 32 $0.082
x64 64 $0.162
x64 96 $0.252
Hardware Core size Prijs / minuut
ARM64 2 $0.005
ARM64 4 $0.008
ARM64 8 $0.014
ARM64 16 $0.026
ARM64 32 $0.050
ARM64 64 $0.98
Hardware Core size Prijs / minuut
GPU-powerd 4 $0.052

Windows

Hardware Core size Prijs / minuut
x64 Server 2 $0.010
x64 Desktop 4 $0.022
x64 Server 8 $0.042
x64 Server 16 $0.082
x64 Server 32 $0.162
x64 Server 64 $0.322
x64 Server 96 $0.552
Hardware Core size Prijs / minuut
ARM64 Desktop 2 $0.008
ARM64 Desktop 4 $0.014
ARM64 Desktop 8 $0.026
ARM64 Desktop 16 $0.050
ARM64 Desktop 32 $0.098
ARM64 Desktop 64 $0.194
Hardware Core size Prijs / minuut
GPU-powerd 4 $0.102

macOS

Hardware Core size Prijs / minuut
x64 4 (Intel) $0.062
x64 12 (Intel) $0.077
Hardware Core size Prijs / minuut
ARM64 3 (M1) $0.062
ARM64 5 (M2 Pro) $0.102

Self hosted

Sinds 1 Januarri 2026 worden er kosten in kaart gebracht voor het hosten van een eigen runner. Deze kosten bedragen $0.002 per minuut, onafhankelijk welk soort model je gebruikt.

Self hosted runner hosten

Op een device kan je standaard één runner hosten via de terminal. Het nadeel hiervan is dat deze terminal altijd open moet staan en dat je er maar één runner kan draaien, wat vervelend is als je bezig bent met meerdere projecten.

De oplossing voor dit probleem is Docker. Hiermee kan je meerdere runners voor één of meerdere GitHub repositories gebruiken. Tijdens dit project wordt er uitleg gegeven over hoe je één of meerdere runners binnen een project kan gebruiken.

Runnen met Docker

Docker-compose.yml

Docker-compose.yml zorgt ervoor dat docker alle containers, netwerken en variabelen instelt.

services:
              github-runner1:
                build: 
                  context: .
                  args: 
                    GITHUB_PAT: ${GITHUB_PAT}
                  
                container_name: "github-runner1-${PROJECT}"
                restart: unless-stopped 
                environment:
                  RUNNER_URL: ${RUNNER_URL}
                  RUNNER_WORKDIR: /home/runner/_work
                  LABELS: self-hosted,Linux,X64,${PROJECT}
                  EPHEMERAL: 0
                  PROJECT: ${PROJECT}
                  GITHUB_PAT: ${GITHUB_PAT}
                  REPO_OWNER: ${REPO_OWNER}
                  REPO_NAME: ${REPO_NAME}
                  NUMBER: 1
                volumes:
                  - /var/run/docker.sock:/var/run/docker.sock
                networks:
                  - internal

            networks:
              internal:

            volumes:
              gh-pages-data:
              runner-data:
            

Dockerfile

# Waar de runner op draait
            FROM ubuntu:22.04

            # Default antwoorden worden door gegeven op vragen
            ENV DEBIAN_FRONTEND=noninteractive

            # GitHub Personal Acces Token (PAT) ophalen uit de .env file
            ARG GITHUB_PAT
            ENV GITHUB_PAT=${GITHUB_PAT}

            # Tijdszone instellen
            ENV TZ=Europe/Amsterdam
            RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

            # Standaard installaties voor het opzetten van de runner
            RUN apt-get update && apt-get install -y \
                sudo \
                curl \
                jq \
                git \
                ca-certificates \
                gnupg \
                lsb-release \
                libicu70 && \
                rm -rf /var/lib/apt/lists/*

            # Een non-root gebruiker 'runner' aanmaken met sudo rechten
            RUN useradd -m runner && echo "runner ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

            # Werkmap bepalen
            WORKDIR /home/runner

            # Code om de runner automatisch te laten registreren 
            RUN ARCH=$(uname -m) && \
              # Type architectuur vaststellen 
                case "$ARCH" in \
                  x86_64) ARCH="x64" ;; \
                  aarch64|arm64) ARCH="arm64" ;; \
                  armv7l|armhf) ARCH="arm" ;; \
                  *) echo "Unsupported architecture: $ARCH"; exit 1 ;; \
                esac && \
                echo "Detected architecture: $ARCH" && \
                # Download URL voor runner vast stellen
                RUNNER_URL=$(curl -s \
                  -H "Authorization: token ${GITHUB_PAT}" \
                  https://api.github.com/repos/actions/runner/releases/latest \
                  | jq -r ".assets[] | select(.name | contains(\"linux-$ARCH\") and endswith(\".tar.gz\")) | .browser_download_url") && \
                echo "Downloading: $RUNNER_URL" && \
                # Runner downloaden (Gecomprimeerd bestand)
                curl -L -H "Authorization: token ${GITHUB_PAT}" \
                  -o actions-runner.tar.gz "$RUNNER_URL" && \
                # Gecomprimeerd bestand uitpakken en verwijderen
                tar xzf actions-runner.tar.gz && rm actions-runner.tar.gz

            # Vanaf hier alle commando's uitvoeren als de 'runner' gebruiker
            USER runner

            # Zorgen dat het script uitvoerbaar is en eventuele Windows-regeleinden (CRLF) verwijderen
            COPY --chown=runner:runner entrypoint.sh /home/runner/entrypoint.sh

            RUN sudo apt-get update && \
                sudo apt-get install -y sed && \
                sed -i 's/\r//g' /home/runner/entrypoint.sh && \
                chmod +x /home/runner/entrypoint.sh

            ENTRYPOINT ["/home/runner/entrypoint.sh"]

entrypoint.sh

#!/bin/bash
            set -e
            # Tijdszone goed zetten voor shellscript
            export TZ=${TZ:-Europe/Amsterdam}


            cleanup() {
              echo "Runner wordt afgemeld bij GitHub..."

              REMOVE_TOKEN=$(curl -sX POST \
                  -H "Authorization: token ${GITHUB_PAT}" \
                  "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/actions/runners/remove-token"
             | jq -r .token)

              if [ -z "$REMOVE_TOKEN" ]; then
                echo "Kon geen removal-token ophalen (handmatig verwijderen)."
                return
              fi

              ./config.sh remove --unattended --token "$REMOVE_TOKEN" || true
            }

            trap cleanup EXIT SIGINT SIGTERM

            RUNNER_TOKEN=$(curl -sX POST \
              -H "Authorization: token ${GITHUB_PAT}" \
              https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/actions/runners/registration-token \
              | jq -r .token)

            if [ -z "$RUNNER_TOKEN" ] || [ -z "$RUNNER_URL" ]; then
              echo "ERROR: RUNNER_TOKEN en RUNNER_URL moeten ingesteld zijn."
              exit 1
            fi

            UTC_TS=$(date -u '+D%dM%mY%Y H%HM%MS%S UTC')
            RUNNER_NAME="${REPO_NAME}-${NUMBER}-${UTC_TS}"

            echo "=========================================="
            echo "Project: $REPO_NAME"
            echo "Runner naam: $RUNNER_NAME"
            echo "Runner URL: $RUNNER_URL"
            echo "=========================================="

            echo "Controleer of runner al geconfigureerd is..."
            if [ ! -f .runner ]; then
              echo "Configureren runner $RUNNER_NAME voor $RUNNER_URL"
              
              if [ "$EPHEMERAL" = "1" ]; then
                EXTRA_ARGS="--ephemeral"
              fi

              ./config.sh \
                --url "$RUNNER_URL" \
                --token "$RUNNER_TOKEN" \
                --name "$RUNNER_NAME" \
                --work _work \
                --labels "$LABELS" \
                --unattended \
                $EXTRA_ARGS
            else
              echo "Runner al geconfigureerd, sla config stap over."
            fi

            echo "=========================================="
            echo "Runner $RUNNER_NAME gestart..."
            echo "=========================================="
            exec ./run.sh

start_runner.sh

Start runner.sh is en script waardoor er geen gebruik gemaakt hoeft te worden van de Docker commants om de runner snel aan te zetten

#!/bin/bash
            set -e
            cd "$(dirname "$0")"

            PROJECT=$(basename "$(dirname "$(dirname "$PWD")")" | tr '[:upper:]' '[:lower:]')
            IMAGE_NAME="${PROJECT}-github-runner"

            echo "--- Start runner voor project: $PROJECT ---"

            # Controleer of image al bestaat — bouwen indien nodig
            if ! docker image inspect "$IMAGE_NAME:latest" >/dev/null 2>&1; then
                echo "Geen bestaande image gevonden — bouwen..."
                PROJECT="$PROJECT" docker compose -p "$PROJECT" build --progress=plain
            else
                echo "Image $IMAGE_NAME bestaat al."
            fi

            # ontainers starten in de achtergrond
            echo "Containers starten..."
            PROJECT="$PROJECT" docker compose -p "$PROJECT" up -d

            # ogs streamen totdat de verbinding is bevestigd
            echo "Wachten op verbinding met GitHub..."

            PROJECT="$PROJECT" docker compose -p "$PROJECT" logs -f --no-log-prefix | grep -m 1 "Connected to GitHub"

            echo -e "\n--- Runner is succesvol verbonden met GitHub! ---"

stop_runner.sh

Stop runner.sh is en script waardoor er geen gebruik gemaakt hoeft te worden van de Docker commants om de runner te laten deregistreren en te verwijderen

#!/bin/bash
            PROJECT=$(basename "$(dirname "$(dirname "$PWD")")" | tr '[:upper:]' '[:lower:]')

            echo "--- Stoppen en afmelden van runner project: $PROJECT ---"

            PROJECT="$PROJECT" docker compose -p "$PROJECT" logs -f --no-log-prefix &
            LOGS_PID=$!

            PROJECT="$PROJECT" docker compose -p "$PROJECT" down --rmi local --remove-orphans

            sleep 2
            kill $LOGS_PID 2>/dev/null

            echo -e "\n--- Runner is succesvol afgemeld en verwijderd! ---"