website-and-documentation/content/en/docs/components/forgejo/actions/runner-orchestration.md
Manuel Ganter 88d3aee150
Some checks failed
Hugo Site Tests / test (push) Failing after 2s
ci / build (push) Successful in 54s
introduced runner orchestration doc
2025-12-02 09:15:05 +01:00

8 KiB

title linkTitle weight description
Runner Orchestration Runner Orchestration 30 GARM

Overview

GARM provides on-demand runner orchestration for Forgejo Actions through dynamic autoscaling. As Forgejo has similar API structure to Gitea (from which it was forked), GARM's Gitea/GitHub compatibility makes it a natural fit for automated runner provisioning. GARM supports custom providers, enabling runner infrastructure deployment across multiple cloud and infrastructure platforms.

A custom edge-connect provider was implemented for GARM to enable infrastructure provisioning. Additionally, Forgejo was adapted to align more closely with Gitea's API, ensuring seamless integration with GARM's orchestration capabilities.

Key Features

  • Autoscales Forgejo Actions runners dynamically based on workload demand
  • Leverages edge-connect infrastructure for distributed runner provisioning

Purpose in EDP

  • Provides CI/CD infrastructure for all software development projects
  • Enhances the EDP platform capabilities through improved Forgejo automation
  • Enables teams to focus on development by consuming platform-managed runners without capacity planning concerns

Repository

Code:

Documentation: [Link to component-specific documentation]

Getting Started

Prerequisites

  • Container Runtime installed (e.g. docker)
  • Forgejo, Gitea or Github

Quick Start

  1. Clone the GARM Provider repository
  2. Build the Docker image: docker buildx build -t <your-image-tag> .
  3. Push the image to your container registry
  4. Deploy GARM using the deployment script from the infra-deploy repository, targeting your Kubernetes cluster: ./local-helm.sh --garm

Verification

  • Verify the GARM pod is running: kubectl get pods -n garm
  • Retrieve the GARM domain endpoint: kubectl get ing -n garm
  • Get the GARM admin password: kubectl get secret -n garm garm-credentials -o json | jq .data.GARM_ADMIN_PASSWORD -r | base64 -d
  • Configure endpoints, credentials, repositories, and runner pools in GARM as described in TODO

Usage Examples

[Use Case 1]

[Example with code/commands showing common use case]

# Example commands

[Use Case 2]

[Another common scenario]

Integration Points

  • [Forgejo]: Picks up pending action jobs, listen in Forgejo
  • [Edge Connect]: Uses this infrastructure to deploy runners that can pick up open jobs in forgejo

Architecture

The primary technical innovation was the integration of GARM to enable ephemeral, scalable runners. This required extending Forgejo's capabilities to support GitHub-compatible runner registration and webhook events.

Workflow Architecture:

  1. Event: A workflow event occurs in Forgejo.
  2. Trigger: A webhook notifies GARM.
  3. Provisioning: GARM spins up a fresh, ephemeral runner.
  4. Execution: The runner registers via the API, executes the job, and is terminated immediately after, ensuring a clean build environment.
sequenceDiagram
    participant User
    participant Forgejo
    participant GARM
    participant Runner as Ephemeral Runner

    User->>Forgejo: Push Code / Trigger Event
    Forgejo->>GARM: Webhook Event (Workflow Dispatch)
    GARM->>Forgejo: Register Runner (via API)
    GARM->>Runner: Spin up Instance
    Runner->>Forgejo: Request Job
    Forgejo->>Runner: Send Job Payload
    Runner->>Runner: Execute Steps
    Runner->>Forgejo: Report Status
    GARM->>Runner: Terminate (Ephemeral)

Sequence Diagrams

[Add sequence diagrams showing key interaction flows with other components]

The diagram below shows how a trigger of an action results in deployment of a runner on edge-connect.

sequenceDiagram

    rect rgb(255,200,200)
    Forgejo->>GARM: (Webhook) A new job is pending
    GARM->>GARM Provider Edge Connect: Create new runner
    GARM Provider Edge Connect->>Edge Connect: Create App
    GARM Provider Edge Connect->>Edge Connect: Create AppInstance
    Edge Connect->>Runner: Deploys
    end

    Runner->>GARM: Retrieve runner registration token
    GARM->>Forgejo: Retrieve runner registration token
    Forgejo-->>GARM: Token
    GARM-->>Runner: Token
    Runner->>Forgejo: Register runner
    Runner->>Forgejo: Fetch job
    Runner->>Runner: Work on job
    Runner->>Forgejo: Send result

Deployment Architecture

[Add infrastructure and deployment diagrams showing how the component is deployed]

TODO c4

  • Garm Container in OTC Kubernetes
  • Garm-Provider in Garm Container
  • Garm in Garm container
  • EDP in OTC Kubernetes
  • Forgejo Runner in Edge Connect
  • EDP --notifies with webhook--> Garm
  • Garm --calls--> EDP
  • Garm --calls--> garm provider
  • garm provider --provisions instance--> Forgejo runner
  • Forgejo runner --retrieves bootstrap information-->Garm
  • Forgejo runner --picks up job--> EDP

Configuration

Provider Setup

The config below configures an external provder for garm. Especially important is the provider.external.config_file which refers to the configuration of the external provider (example below) and provider.external.provider_executable which needs to point to the provider executable.

# config.toml
...
[[provider]]
name = "edge-connect"
description = "edge connect provider"
provider_type = "external"

[provider.external]
config_file = "/etc/garm/edge-connect-provider-config.toml"
provider_executable = "/opt/garm/providers.d/garm-provider-edge-connect"
environment_variables = ["EDP_EDGE_CONNECT_"]
# edge-connect-provider-config.toml
log_file = "/garm/provider.log"
credentials_file = "/etc/garm-creds/credentials.toml" # to authenticate agains edge_connect.url

[edge_connect]
organization = "edp-developer-framework"
region = "EU"
url = "https://hub.apps.edge.platform.mg3.mdb.osc.live"
default_flavor = "EU.small"

[edge_connect.cloudlet]
name = "Munich"
organization = "TelekomOP"
# credentials.toml for edge connect platform
username = ""
password = ""

Runner Pool Configuration

Once the configuration is in place and garm has been deployed. You can connect garm to Forgejo/Gitea/Github, using the commands below. If you have a forgejo instance, you want to create a gitea endpoint.

# https://edp.buildth.ing/DevFW/garm-deploy/src/branch/master/helm/garm/templates/init-job.yaml#L39-L56
garm-cli init --name gitea --password ${GARM_ADMIN_PASSWORD} --username ${GARM_ADMIN_USERNAME} --email ${GARM_ADMIN_EMAIL} --url ${GARM_URL}
if [ $? -ne 0 ]; then
  echo "garm maybe already initialized"
  exit 0
fi

# API_GIT_URL=https://garm-provider-test.t09.de/api/v1
# GIT_URL=https://garm-provider-test.t09.de
garm-cli gitea endpoint create \
--api-base-url ${API_GIT_URL} \
--base-url ${GIT_URL} \
--description "My first Gitea endpoint" \
--name local-gitea

garm-cli gitea credentials add \
--endpoint local-gitea \
--auth-type pat \
--pat-oauth-token $GITEA_TOKEN \
--name autotoken \
--description "Gitea token"

Now, connect to the WebUI, use GARM_ADMIN_USERNAME and GARM_ADMIN_PASSWORD as credentials to authenticate. Click on repositories and

Troubleshooting

[Common Issue 1]

Problem: [Description]

Solution: [How to fix]

[Common Issue 2]

Problem: [Description]

Solution: [How to fix]

Status

Maturity: [Production / Beta / Experimental]

Additional Resources

  • Using garm
  • [Link to community resources]
  • [Link to related components]

Documentation Notes

[Instructions for team members filling in this documentation - remove this section once complete]