A Forgejo Runner plugin that spawn jobs as Kubernetes pods
kubernetes ci forgejo runner

Files
README.md

kuranto #

Caution

Kuranto is at an early stage of development, and implements an experimental feature of the Forgejo Runner, use at your own risks.

kuranto implements Forgejo Runner v13's experimental plugin.v1alpha.BackendPlugin gRPC interface. It creates one Kubernetes Pod per Actions job and executes workflow commands using the Kubernetes pods/exec subresource.

The Forgejo plugin protocol is alpha. This implementation currently targets Forgejo Runner v13.2.0.

Execution model #

kuranto runs as a container alongside the Forgejo Runner in one pod. The runner talks to kuranto through its gRPC plugin interface. When picking up jobs, the runner instructs the plugin to execute it; kuranto then creates job pods in its configured namespace.

A job pod is:

  • a job container using the label's image, or the workflow's configured image;
  • an emptyDir mounted on /shared for ephemeral storage during job execution, and a writable /tmp;
  • optional service containers as sidecars, reachable by their service name on 127.0.0.1

Service port mappings are unsupported by Kuranto. Because service containers share the job Pod's network, services are reached on the ports they listen on; Kuranto does not publish or translate workflow host/container port mappings. A service definition with ports will be rejected.

The job pod has no access to the Kubernetes cluster, and empty service account is mounted, which has no permissions at all.

Configuration #

The plugin reads these environment variables:

Variable Required Default Purpose
KURANTO_KUBERNETES_NAMESPACE yes — Dedicated namespace in which it may create job Pods.
KURANTO_LISTEN_ADDR no 0.0.0.0:50051 gRPC listener.
KURANTO_LOG_LEVEL no info Minimum log level: trace, debug, info, warn, or error.
KURANTO_DEFAULT_JOB_IMAGE no data.forgejo.org/oci/node:lts Used if the runner sends no image.
KURANTO_JOB_SERVICE_ACCOUNT no none Service account assigned to generated job Pods. It should have no Kubernetes RBAC by default.
KURANTO_JOB_NODE_SELECTOR no none JSON object mapping node label names to string values for every generated job Pod's nodeSelector.
KURANTO_JOB_AFFINITY no none JSON object using Kubernetes' native affinity structure for every generated job Pod. Supports node affinity and Pod affinity/anti-affinity.
KURANTO_JOB_TOLERATIONS no none JSON array of Kubernetes toleration objects for every generated job Pod.
KURANTO_JOB_CPU_REQUEST no none CPU request for each generated primary job container, for example 250m.
KURANTO_JOB_MEMORY_REQUEST no none Memory request for each generated primary job container, for example 512Mi.
KURANTO_JOB_CPU_LIMIT no none CPU limit for each generated primary job container, for example 1.
KURANTO_JOB_MEMORY_LIMIT no none Memory limit for each generated primary job container, for example 1Gi.
KURANTO_SERVICE_CPU_REQUEST no none CPU request for each generated service container, for example 100m.
KURANTO_SERVICE_MEMORY_REQUEST no none Memory request for each generated service container, for example 128Mi.
KURANTO_SERVICE_CPU_LIMIT no none CPU limit for each generated service container, for example 500m.
KURANTO_SERVICE_MEMORY_LIMIT no none Memory limit for each generated service container, for example 512Mi.
KURANTO_POD_CPU_REQUEST no none CPU request for the generated Pod, for example 1. Requires Kubernetes 1.34 or later.
KURANTO_POD_MEMORY_REQUEST no none Memory request for the generated Pod, for example 2Gi. Requires Kubernetes 1.34 or later.
KURANTO_POD_CPU_LIMIT no none CPU limit for the generated Pod, for example 2. Requires Kubernetes 1.34 or later.
KURANTO_POD_MEMORY_LIMIT no none Memory limit for the generated Pod, for example 4Gi. Requires Kubernetes 1.34 or later.
KURANTO_MAX_ENVIRONMENT_TIMEOUT_SECONDS no 10800 Upper bound for a job Pod's activeDeadlineSeconds.

Resource values use Kubernetes quantity syntax. Each request and limit is optional and omitted when unset. Job settings apply to the primary job container; service settings apply to every service container. Pod settings populate Pod-level resources and require Kubernetes 1.34 or later, where PodLevelResources is enabled by default. When a pod CPU or memory limit is set, the sum of that resource's job and service container limits must not exceed it.

Set KURANTO_LOG_LEVEL=debug to enable detailed Kuranto logs.

Job scheduling #

By default, job pods are scheduled as regular pods without any particular constraints.

Using the variables described above, you can configure nodeSelector, affinity, and tolerations. These will be set on the pods created for jobs, and will influence how they are scheduled in the cluster.

See the Helm scheduling examples or the manual JSON configuration for more details on this.

Installation #

For a quick start with Helm, check out the getting started documentation.

For manual deployment, see these instructions.

Development #

This repository provides two main ways of provisioning a development environment:

Nix #

You need to have flakes enabled in your Nix installation.

If you have direnv, just run direnv allow to load everything you need to work on Kuranto.

Otherwise, just run nix develop.

Mise #

Run mise trust and mise install to get all the tools and the Rust toolchain.

Develop #

You can run unit tests using:

cargo test --lib --bins

End-to-end tests require KinD (provided by Nix or Mise), and can be run using:

./scripts/e2e.sh