Using Forgejo Actions (Self-hosted)

Actions is a continuous integration and continuous delivery (CI/CD) feature that allows you to automate your build, test and deployment pipelines in Forgejo, the software Codeberg uses. For more information, please read Forgejo's Documentation.

Due to outstanding security issues and bus factor (we need more maintainers for our CI service), we are currently providing hosted Actions in limited fashion: see https://codeberg.org/actions/meta. If you need Codeberg to host your CI, please use Woodpecker CI instead.

But you can already connect your own Runner to Codeberg. CI jobs will run on your machine, and the result will be displayed in Codeberg.

This guide will walk you through setting up your own Forgejo Actions Runner to use for CI jobs.

Obtaining a registration token

Make sure to enable actions

Repository Actions are disabled by default and will require you to enable them in the "Advanced Settings" section of the settings page.

Before deploying the Runner, you need to obtain a registration token from Codeberg. Registration tokens are used by the Runner and Codeberg to share secrets and configurations.

You can add Runners to your account, organization, or repository. Choosing where you obtain the registration token will determine where your Runner will accept workflows from.

  1. Go to the account/organization/repository settings page.

  2. Click on Actions.

  3. Click on Runners.

  4. Click on Create new Runner.

  5. Copy the registration token.

Create new Runner

Installing Forgejo Runner

Forgejo Runner is released in both binary and container image (OCI) forms:

  • Get the last released version:

    $ export RUNNER_VERSION=$(curl -X 'GET' https://code.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | jq .name -r | cut -c 2-)

    You can also manually check directly on the Forgejo Runner release page

  • Download the binary to run on your machine:

    $ wget -O forgejo-runner https://code.forgejo.org/forgejo/runner/releases/download/v${RUNNER_VERSION}/forgejo-runner-${RUNNER_VERSION}-linux-amd64
    $ chmod +x forgejo-runner

    Make sure to replace amd64 with arm64 if your host machine is on ARM.

  • Or download the container image and run it using Docker:

    $ docker run --rm code.forgejo.org/forgejo/runner:${RUNNER_VERSION} forgejo-runner --version
    forgejo-runner version <runner version>

Preparing configuration files

Before you deploy the Runner, you need to generate its configuration files and modify as suited.

You can generate them to your current directory by either running the binary on host or in a Docker container.

Make sure to replace {TOKEN} with the registration token you copied, and {NAME} with any identifier to monitor it on Codeberg.

Binary

$ ./forgejo-runner register --no-interactive --token {TOKEN} --name {NAME} --instance https://codeberg.org
INFO Registering runner, arch=amd64, os=linux, version=<runner version>.
DEBUG Successfully pinged the Forgejo instance server
INFO Runner registered successfully.
$ ./forgejo-runner generate-config > config.yml

Docker

$ docker run -v /var/run/docker.sock:/var/run/docker.sock  -v $PWD:/data --rm code.forgejo.org/forgejo/runner:${RUNNER_VERSION} forgejo-runner register --no-interactive --token {TOKEN} --name {NAME} --instance https://codeberg.org
Status: Downloaded newer image for code.forgejo.org/forgejo/runner:<runner version>
level=info msg="Registering runner, arch=arm64, os=linux, version=<runner version>."
level=warning msg="Runner in user-mode."
level=debug msg="Successfully pinged the Forgejo instance server"
level=info msg="Runner registered successfully."
$ docker run -v /var/run/docker.sock:/var/run/docker.sock  -v $PWD:/data --rm code.forgejo.org/forgejo/runner:${RUNNER_VERSION} forgejo-runner generate-config > config.yml

These commands will generate two files in your current directory:

  • .runner which is the configuration file produced when registering the runner.

  • config.yml which is the main configuration file with defaults in place you can modify to suit your needs and environment.

Deployment Methods

Depending on your setup and your security needs, there is a wide variety of options for deploying the Runner.

Running on Docker

This method uses the host Docker server by mounting the socket.

Podman compatibility

Podman can work by executing:

$ podman system service -t 0 &

$ DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock ./forgejo-runner daemon

Since this method requires access to the Docker socket, you will need to get the GID of the Docker group (usually docker) in your host machine by running:

$ id | grep -Po '\d+\(docker\)'
$ 996(docker)

Make sure to replace 996 with the Docker group GID of the host in the following command:

$ docker run -d -v /var/run/docker.sock:/var/run/docker.sock --user 1000:996 -v $PWD:/data --rm code.forgejo.org/forgejo/runner:${RUNNER_VERSION} forgejo-runner --config config.yml daemon
22eae46a021294a213e7f733203f7551250b67367c7507b53b5fd427f0f82d2e

Now your CI Runner should be running in a new container.

Running on Docker in Docker

Using Docker Compose, we can configure the Runner container to execute workflows inside another layer of containers (Docker-in-Docker).

Here is an example snippet of how it can be configured. It will automatically use the latest version of the runner, feel free to specify the version of the forgejo runner if you need:

version: '3'

services:
  docker:
    image: docker:dind
    privileged: true
    volumes:
      - certs:/certs

  runner:
    image: code.forgejo.org/forgejo/runner
    environment:
      DOCKER_HOST: tcp://docker:2376
      DOCKER_TLS_VERIFY: 1
      DOCKER_CERT_PATH: /certs/client
    volumes:
      - /opt/forgejo-runner:/data
      - certs:/certs
    command: 'forgejo-runner --config config.yml daemon'
volumes:
  certs:

Make sure to replace /opt/forgejo-runner with the directory path of your configuration files.

Running on Kubernetes

Warning

Docker in Docker (dind) requires elevated privileges on Kubernetes.

The current way to achieve this is to set the pod SecurityContext to privileged.

Keep in mind that this is a potential security issue that can allow a malicious application to break out of the container context.

Here is an example snippet of how it can be configured. It will automatically use the latest version of the runner, feel free to specify the version of the forgejo runner if you need:

apiVersion: v1
stringData:
  token: your_registration_token
kind: Secret
metadata:
  name: runner-secret
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: forgejo-runner
  name: forgejo-runner
spec:
  replicas: 2
  selector:
    matchLabels:
      app: forgejo-runner
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: forgejo-runner
    spec:
      restartPolicy: Always
      volumes:
        - name: docker-certs
          emptyDir: {}
        - name: runner-data
          emptyDir: {}
      initContainers:
        - name: runner-config-generation
          image: code.forgejo.org/forgejo/runner
          command:
            ['forgejo-runner create-runner-file --instance $FORGEJO_INSTANCE_URL --secret $RUNNER_SECRET --connect']
          env:
            - name: RUNNER_SECRET
              valueFrom:
                secretKeyRef:
                  name: runner-secret
                  key: token
            - name: FORGEJO_INSTANCE_URL
              value: https://codeberg.org
          volumeMounts:
            - name: runner-data
              mountPath: /data
      containers:
        - name: runner
          image: code.forgejo.org/forgejo/runner
          command:
            [
              'sh',
              '-c',
              "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; forgejo-runner daemon",
            ]
          env:
            - name: DOCKER_HOST
              value: tcp://localhost:2376
            - name: DOCKER_CERT_PATH
              value: /certs/client
            - name: DOCKER_TLS_VERIFY
              value: '1'
          volumeMounts:
            - name: docker-certs
              mountPath: /certs
            - name: runner-data
              mountPath: /data
        - name: daemon
          image: docker:dind
          env:
            - name: DOCKER_TLS_CERTDIR
              value: /certs
          securityContext:
            privileged: true
          volumeMounts:
            - name: docker-certs
              mountPath: /certs

Make sure to replace the value of token with your registration token.

Running on host machine

Warning

There is no isolation at all and a single job can permanently destroy the host.

$ ./forgejo-runner --config config.yml daemon
INFO[0000-00-00T00:00:00Z] Starting runner daemon

Now your CI Runner should running on your host machine.

Testing workflows

To test your CI runner setup, you can use the following demo workflow:

on: [push]
jobs:
  test:
    runs-on: docker
    steps:
      - run: echo All Good

The runner seeks action recipes from .forgejo/workflows, so make sure your file is in the required path.

Demo workflow running successfully

References


Hey there! 👋 Thank you for reading this article!

Is there something missing, or do you have an idea on how to improve the documentation? Do you want to write your own article?

You're invited to contribute to the Codeberg Documentation at its source code repository, for example, by adding a pull request or joining in on the discussion in the issue tracker.

For an introduction on contributing to Codeberg Documentation, please have a look at the Contributor FAQ.

© Codeberg Docs Contributors. See LICENSE