Skip to content

bitdeps/actions-runner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

actions-runner

GitHub Actions runner and images based on Podman.

Podman 5.x

The Bitdeps Actions Runner uses a statically built version of Podman, which differs from the official Microsoft runner and offers unique features. Unlike the official runner, this version provides:

  • Rootless execution on Kubernetes with minimal capabilities (only SETUID and SETGID are used).
  • No need for Buildx — efficient multi-architecture builds are supported out of the box.
  • Container-only job execution — this runner is designed exclusively for container jobs.
  • Pre-configured tools:
    • A Docker compatibility wrapper for remote Podman execution inside any job container.
    • GitHub CLI tool.
    • Pre-configured Google Artifacts Registry credential helper.

Known Limitations

Rootless execution in cloud environments like GKE has some limitations. For instance, port mapping and DNS for service containers do not work as expected. Podman relies on the CNI plugin, and Netavark does not function well in cloud environments. Despite this, the overall user experience remains smooth.

Using Podman Actions

Since this runner does not use Buildx or Docker, Podman-native actions are used instead. Here are some examples:

jobs:
  build:
    runs-on: myrunner

    permissions:
      contents: read
      packages: write

    ## Container jobs are only allowed!
    container:
      image: images/alpine:latest

    steps:
      - name: Build Image
        id: build-image
        uses: redhat-actions/buildah-build@v2
        with:
          image: myorg/repo
          context: .
          tags: latest
          build-args: ""
          containerfiles: Containerfile

      - name: Push to Artifact Registry
        uses: redhat-actions/push-to-registry@v2
        with:
          image: myorg/repo
          tags: latest
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}

For more information:

Deploying on Kubernetes

The standard method for deploying self-hosted runners in Kubernetes is using actions-runner-controller. For detailed setup, refer to the official documentation.

Further configuration details are provided below.

Fuse Device Plugin

With the Fuse device plugin, pods no longer need to run in privileged mode to access /dev/fuse. The DaemonSet below injects the fuse device into pods running on matched nodes. Learn more.

apiVersion: apps/v1
kind: DaemonSet
spec:
  template:
    spec:
      hostNetwork: true
      nodeSelector:
        myorg/gh-runner: "true"
      tolerations:
      - key: myorg/gh-runner
        operator: Exists
        effect: NoSchedule
      containers:
      - image: soolaugust/fuse-device-plugin:v1.0
        name: fuse-device-plugin-ctr
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
        volumeMounts:
          - name: device-plugin
            mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins

Actions Runner Controller Values

Refer to the values.yaml for configuration reference. The configuration below highlights important settings, such as the Fuse device plugin, virtual network interface, and AppArmor security profile.

template:
  metadata:
    annotations:
      container.apparmor.security.beta.kubernetes.io/runner: unconfined
      cluster-autoscaler.kubernetes.io/safe-to-evict: "true"

  spec:
    serviceAccountName: scale-set-wi

    nodeSelector:
      myorg/gh-runner: "true"

    tolerations:
    - key: myorg/gh-runner
      operator: Exists
      effect: NoSchedule

    containers:
    - name: runner
      command:
        - entrypoint.sh
        - /home/runner/run.sh
      imagePullPolicy: Always
      image: ghcr.io/bitdeps/actions-runner:5.3.1

      securityContext:
        runAsUser: 1001
        runAsGroup: 1001
        fsGroup: 1001
        capabilities:
          allowPrivilegeEscalation: false
          drop: ["ALL"]
          add:
            - SETUID
            - SETGID

      resources:
        requests:
          cpu: 500m
          memory: 3350Mi

        limits:
          github.com/fuse: 1
          cpu: 2
          memory: 3350Mi

      volumeMounts:
        - mountPath: /home/runner/.local/share/containers
          name: podman-local

        # Virtual network interfaces mount
        - mountPath: /dev/net/tun
          name: dev-tun

        # Additional registry shortnames for Podman
        - name: shortnames
          mountPath: "/etc/containers/registries.conf.d/001-shortnames.conf"
          subPath: 001-shortnames.conf
          readOnly: true

    volumes:
      - name: podman-local
        emptyDir: {}

      - name: dev-tun
        hostPath:
          path: /dev/net/tun
          type: CharDevice

      - name: shortnames
        configMap:
          name: scale-set-configs-shortnames