Skip to content

Build Runner

Our runner for builds and everything that isn't GitOps. It runs on a shared stagefreight docker network with three long-lived services plus a one-shot registration:

  • DinD — the Docker daemon builds talk to, exposing a TLS endpoint at tcp://dind:2376. Job containers receive DOCKER_HOST + DOCKER_TLS_VERIFY + the client certs.
  • BuildKit (buildkitd) — for buildx builds. It generates its own independent PKI (CA / server / client certs) on first boot — separate from DinD — and serves tcp://buildkitd:1234 with --oci-worker-gc storage limits.
  • GitLab runner — docker executor, joined to the stagefreight network.
  • The StageFreight cache is a host volume (/opt/docker/gitlab-runner/stagefreight) mounted into DinD, BuildKit, and job containers at /stagefreight.

Why BuildKit gets its own PKI

The buildkitd-certs init container mints a CA and server/client certs scoped to DNS:buildkitd so BuildKit's TLS is fully independent of DinD's — the two daemons don't share trust.

services:
  dind:
    image: docker:dind
    privileged: true
    restart: always
    environment:
      DOCKER_TLS_CERTDIR: /certs
      DOCKER_TLS_SAN: DNS:dind
    volumes:
      - dind-storage:/var/lib/docker
      - /opt/docker/gitlab-runner/certs:/certs
      - /opt/docker/gitlab-runner/stagefreight:/stagefreight
    healthcheck:
      test: ["CMD", "docker", "info"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 5s
    networks:
      stagefreight:
        aliases:
          - dind

  buildkitd-certs:
    image: docker.io/library/alpine:3
    restart: "no"
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        if [ -f /out/server/cert.pem ]; then
          echo "BuildKit PKI already exists, skipping"
          exit 0
        fi
        apk add --no-cache openssl >/dev/null 2>&1
        echo "Generating independent BuildKit PKI..."
        mkdir -p /out/ca /out/server /out/client

        # CA
        openssl genrsa -out /out/ca/key.pem 4096 2>/dev/null
        openssl req -new -x509 -key /out/ca/key.pem -out /out/ca/cert.pem \
          -days 3650 -subj "/CN=BuildKit CA" 2>/dev/null

        # Server cert (SAN: DNS:buildkitd)
        openssl genrsa -out /out/server/key.pem 4096 2>/dev/null
        openssl req -new -key /out/server/key.pem -out /tmp/server.csr \
          -subj "/CN=buildkitd" 2>/dev/null
        printf "[v3]\nsubjectAltName=DNS:buildkitd,DNS:localhost,IP:127.0.0.1" > /tmp/ext.cnf
        openssl x509 -req -in /tmp/server.csr \
          -CA /out/ca/cert.pem -CAkey /out/ca/key.pem -CAcreateserial \
          -out /out/server/cert.pem -days 3650 \
          -extensions v3 -extfile /tmp/ext.cnf 2>/dev/null

        # Client cert
        openssl genrsa -out /out/client/key.pem 4096 2>/dev/null
        openssl req -new -key /out/client/key.pem -out /tmp/client.csr \
          -subj "/CN=buildkit-client" 2>/dev/null
        openssl x509 -req -in /tmp/client.csr \
          -CA /out/ca/cert.pem -CAkey /out/ca/key.pem -CAcreateserial \
          -out /out/client/cert.pem -days 3650 2>/dev/null
        cp /out/ca/cert.pem /out/client/ca.pem

        echo "BuildKit PKI generated (independent from DinD)"
    volumes:
      - /opt/docker/gitlab-runner/buildkitd-certs:/out

  buildkitd:
    image: moby/buildkit:latest
    privileged: true
    restart: always
    depends_on:
      buildkitd-certs:
        condition: service_completed_successfully
    command:
      - --addr
      - tcp://0.0.0.0:1234
      - --tlscacert=/certs/ca/cert.pem
      - --tlscert=/certs/server/cert.pem
      - --tlskey=/certs/server/key.pem
      - --oci-worker-gc=true
      - --oci-worker-gc-keepstorage=12000
    volumes:
      - buildkitd-state:/var/lib/buildkit
      - /opt/docker/gitlab-runner/stagefreight:/stagefreight
      - /opt/docker/gitlab-runner/buildkitd-certs:/certs:ro
    healthcheck:
      test: ["CMD-SHELL", "buildctl --addr tcp://127.0.0.1:1234 --tlscacert /certs/ca/cert.pem --tlscert /certs/client/cert.pem --tlskey /certs/client/key.pem debug workers"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    networks:
      stagefreight:
        aliases:
          - buildkitd

  register-runner:
    image: gitlab/gitlab-runner:latest
    restart: "no"
    depends_on:
      dind:
        condition: service_healthy
      buildkitd:
        condition: service_healthy
    entrypoint: ["/bin/sh", "-c"]
    command:
      - |
        if [ ! -f /etc/gitlab-runner/config.toml ]; then
          echo "Config does not exist, registering runner..."
          gitlab-runner register \
            --docker-dns=10.0.0.1 \
            --docker-dns=10.0.0.2 \
            --docker-dns=1.1.1.1 \
            --docker-dns=8.8.8.8 \
            --docker-dns=127.0.0.1 \
            --docker-image=alpine:latest \
            --docker-network-mode=stagefreight \
            --docker-privileged=false \
            --docker-env=DOCKER_HOST=tcp://dind:2376 \
            --docker-env=DOCKER_TLS_VERIFY=1 \
            --docker-env=DOCKER_CERT_PATH=/certs/client \
            --docker-volumes=/opt/docker/gitlab-runner/stagefreight:/stagefreight \
            --docker-volumes=/opt/docker/gitlab-runner/buildkitd-certs/client:/buildkit-certs:ro \
            --docker-volumes=/opt/docker/gitlab-runner/certs/client:/certs/client:ro \
            --executor=docker \
            --name=$${RUNNER_NAME:-"Build Runner"} \
            --non-interactive \
            --token=$${RUNNER_TOKEN} \
            --url=$${CI_SERVER_URL}
        else
          echo "Runner config already exists, skipping registration"
        fi
    environment:
      - CI_SERVER_URL=${CI_SERVER_URL}
      - RUNNER_TOKEN=${RUNNER_TOKEN}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/docker/gitlab-runner/config:/etc/gitlab-runner:z
    networks:
      - stagefreight

  runner:
    image: gitlab/gitlab-runner:latest
    restart: always
    depends_on:
      dind:
        condition: service_healthy
      buildkitd:
        condition: service_healthy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/docker/gitlab-runner/config:/etc/gitlab-runner:z
    healthcheck:
      test: ["CMD", "gitlab-runner", "list"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    networks:
      - stagefreight

networks:
  stagefreight:
    name: stagefreight

volumes:
  dind-storage:
  buildkitd-state: