---
title: Orchestration with GARM
linkTitle: Orchestration with GARM
weight: 30
description: Using GARM to manage short-lived Forgejo runners
---

## 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**:
- [GARM Provider for Edge Connect](https://edp.buildth.ing/DevFW-CICD/garm-provider-edge-connect)
- [GARM deploy script](https://edp.buildth.ing/DevFW/infra-deploy/src/branch/main/scripts/local-helm.sh)
- [GARM deploy manifests](https://edp.buildth.ing/DevFW/garm-deploy.git)

**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](https://edp.buildth.ing/DevFW-CICD/garm-provider-edge-connect/)
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](https://edp.buildth.ing/DevFW/infra-deploy/src/branch/main/scripts/local-helm.sh) from the [infra-deploy](https://edp.buildth.ing/DevFW/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](TODO)

## 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](https://github.com/cloudbase/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.

```mermaid
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

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

{{<likec4-view view="forgejoGarmInteraction" browser="false" dynamic-variant="sequence" project="architecture" title="Interaction between Forgejo, Garm and Edge Connect">}}

### Deployment Architecture

{{<likec4-view view="forgejoGarmArchitecture" browser="false" dynamic-variant="sequence" project="architecture" title="Architecture of Forgejo, Garm and Edge Connect">}}

[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
# 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
# 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
# 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.

```sh
# 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](https://github.com/cloudbase/garm/blob/main/doc/using_garm.md)

## Documentation Notes

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