Files
gitea-runner-operator/README.md

192 lines
5.1 KiB
Markdown

# Gitea Runner Operator
A Kubernetes Operator to manage ephemeral Gitea Act runners. This operator automatically spawns runner pods based on queued jobs, support global, org/user, repo level runner. Definetely-vibe-coded (don't worry i know what i am doing).
## Features
- **Ephemeral Runners**: Each job gets a fresh runner which is destroyed after execution.
- **Multiple Scopes**: Support for `global`, `org`, `user`, and `repo` level runners.
- **Auto-Scaling**: Automatically scales runners up to a configured maximum based on queued jobs.
- **Label Matching**: matches Gitea job labels (e.g., `ubuntu-latest`) to runner capabilities.
## Prerequisites
- **Kubernetes Cluster**: v1.23+
- **Gitea**: v1.25.0+ (with Actions enabled)
## Installation (Helm Chart)
### Incoming
## Installation (Manual)
### 1. Deploy the Operator
You can deploy the operator using the provided manifests.
```bash
# Clone the repository
git clone https://github.com/bapung/gitea-runner-operator.git
cd gitea-runner-operator
# Install CRDs
make install
# Deploy the controller to the cluster
make deploy IMG=ghcr.io/bapung/gitea-runner-operator:latest
```
### 2. Create Credentials Secret
Create a secret containing the Gitea Registration Token and an API Auth Token.
1. **Registration Token**: Get this from Gitea Admin -> Actions -> Runners -> Create new Runner (or Org/Repo settings).
2. **Auth Token**: Generate a token in Gitea User Settings -> Applications. It needs `read:repository`, `read:user` permissions.
```yaml
apiVersion: v1
kind: Secret
metadata:
name: gitea-runner-secret
namespace: gitea-runner-operator-system
type: Opaque
stringData:
registrationToken: "<YOUR_REGISTRATION_TOKEN>"
authToken: "<YOUR_API_TOKEN>"
```
Apply it:
```bash
kubectl apply -f secret.yaml
```
## Configuration
The core resource is the `RunnerGroup`. Below are examples for different scopes.
### 1. Repository Scope
Spawns runners only for jobs in a specific repository.
```yaml
apiVersion: gitea.bpg.pw/v1alpha1
kind: RunnerGroup
metadata:
name: my-repo-runner
namespace: gitea-runner-operator-system
spec:
scope: repo
org: myorg
repo: myrepo
giteaURL: https://gitea.example.com
maxActiveRunners: 5
labels:
- "ubuntu-latest"
- "custom-label"
registrationToken:
secretRef:
name: gitea-runner-secret
key: registrationToken
authToken:
secretRef:
name: gitea-runner-secret
key: authToken
```
### 2. Organization Scope
Spawns runners for any repository within the organization.
```yaml
apiVersion: gitea.bpg.pw/v1alpha1
kind: RunnerGroup
metadata:
name: my-org-runner
namespace: gitea-runner-operator-system
spec:
scope: org
org: myorg
# repo is omitted
giteaURL: https://gitea.example.com
maxActiveRunners: 10
# ... (tokens)
```
### 3. User Scope
Spawns runners for any repository owned by the specified user.
```yaml
apiVersion: gitea.bpg.pw/v1alpha1
kind: RunnerGroup
metadata:
name: my-user-runner
namespace: gitea-runner-operator-system
spec:
scope: user
user: myusername
# org and repo are omitted
giteaURL: https://gitea.example.com
maxActiveRunners: 3
# ... (tokens)
```
### 4. Global Scope
Spawns runners for any job in the Gitea instance (Admin level).
```yaml
apiVersion: gitea.bpg.pw/v1alpha1
kind: RunnerGroup
metadata:
name: global-runner
namespace: gitea-runner-operator-system
spec:
scope: global
# org, user, and repo are omitted
giteaURL: https://gitea.example.com
maxActiveRunners: 20
# ... (tokens)
```
## How it works
1. The **Controller** polls the Gitea API (using the `authToken`) to check for queued jobs matching the scope and labels.
2. If a matching queued job is found, and the current active runner count is below `maxActiveRunners`, the Controller creates a Kubernetes `Job`.
3. The `Job` pod starts an `act_runner` instance, registers itself using the `registrationToken` (as ephemeral), picks up the job, executes it, and then terminates.
## Troubleshooting
### Runners are not starting
1. **Check Controller Logs**:
```bash
kubectl logs -n gitea-runner-operator-system -l control-plane=controller-manager -f
```
Look for errors regarding API authentication or connectivity.
2. **Check Permissions**:
Ensure the `authToken` has sufficient permissions (`read:repository`, etc.) to query actions.
3. **Check Labels**:
Enable debug logging in the controller to see label matching logic. If your Gitea job requires `ubuntu-latest` but your RunnerGroup defines `centos`, it won't match.
### Docker Daemon Issues
This is a default rootless Job template from Gitea doc, it has issues with docker daemon. I still can't to get it working with `docker` command, other container works just fine if you put correct labels.
Per Gemini:
The default runner image uses `dind-rootless`. This requires the pod to run with `privileged: true`. Ensure your cluster policies (PSP/PSA) allow privileged pods in the operator namespace.
## Roadmap / Wishlist
- Helm Chart
- Custom Runner Job Spec definition
- Push mode using Webhook trigger
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.