Add helm chart

add README
This commit is contained in:
igrikus 2025-08-19 15:27:10 +02:00
parent 004c03962f
commit 351b5e8fed
17 changed files with 860 additions and 0 deletions

View file

@ -71,6 +71,8 @@ Check out the [quickstart](/doc/quickstart.md) document for instructions on how
Thanks to the efforts of the amazing folks at [@mercedes-benz](https://github.com/mercedes-benz/), GARM can now be integrated into k8s via their operator. Check out the [GARM operator](https://github.com/mercedes-benz/garm-operator/) for more details.
In addition to the operator, GARM can also be deployed on Kubernetes using the provided Helm chart. For detailed instructions, please see the [Helm deployment guide](/doc/helm.md).
## Configuring GARM for GHES
GARM supports creating pools and scale sets in either GitHub itself or in your own deployment of [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@3.10/admin/overview/about-github-enterprise-server). For instructions on how to use ```GARM``` with GHE, see the [credentials](/doc/github_credentials.md) section of the documentation.

124
doc/helm.md Normal file
View file

@ -0,0 +1,124 @@
# Deploying GARM with Helm
This document provides instructions on how to deploy GARM on a Kubernetes cluster using the provided Helm chart.
As this chart is not currently published to a public Helm repository, you will need to clone the GARM git repository to deploy it.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.2.0+
- `kubectl` configured to connect to your cluster.
### Admin Credentials
By default, the chart creates a Kubernetes secret to store the admin user\'s credentials (`username`, `password`, `email`), the JWT secret, and the database passphrase.
If you want to use an existing secret, you can specify its name using `garm.admin.secretName`. Ensure the secret contains the necessary keys as defined by `garm.admin.usernameKey`, `garm.admin.passwordKey`, etc.
### Persistence
The chart uses a PersistentVolumeClaim (PVC) to store the GARM database. By default, persistence is enabled. You can disable it by setting `persistence.enabled` to `false`, but this is not recommended for production environments.
### Providers Configuration
You can configure external providers by adding them to the `providers` list in your `values.yaml` file. Each provider entry requires a `name`, `description`, `executable` path, and a `config` block with the provider-specific settings.
Example for a GCP provider:
```yaml
providers:
- name: "gcp"
type: "external"
description: "GCP provider"
executable: "/opt/garm/providers.d/garm-provider-gcp"
config:
project_id: "my-gcp-project"
zone: "us-central1-a"
```
### Forge Credentials (GitHub/Gitea)
The chart\'s initialization script can automatically configure GARM with your GitHub and/or Gitea credentials. To use this feature, you must first create Kubernetes secrets containing your forge credentials.
Then, configure the `forges.github.credentials` or `forges.gitea.credentials` sections in your `values.yaml`.
**GitHub Example:**
First, create a secret:
```bash
kubectl create secret generic my-github-secret \
--from-literal=token='ghp_xxxxxxxx'
```
Then, configure `values.yaml`:
```yaml
forges:
github:
credentials:
- name: "my-github"
secretName: "my-github-secret"
authType: "pat"
tokenKey: "token"
```
**Gitea Example:**
First, create a secret:
```bash
kubectl create secret generic garm-gitea-config \
--from-literal=server-url='https://gitea.example.com' \
--from-literal=access-token='xxxxxxxx'
```
Then, configure `values.yaml`:
```yaml
forges:
gitea:
credentials:
- name: "my-gitea"
secretName: "garm-gitea-config"
urlKey: "server-url"
tokenKey: "access-token"
```
## Installation Steps
The `helm-chart/values.yaml` file serves as a template and is not intended for direct use, as it contains placeholder values. To properly deploy the chart, follow these steps:
1. **Create a custom values file:**
Clone the repository and copy the `values.yaml` to a new file. For example, `my-values.yaml`.
```bash
git clone https://github.com/cloudbase/garm.git
cd garm
cp helm-chart/values.yaml my-values.yaml
```
2. **Configure your deployment:**
Edit `my-values.yaml` and modify the parameters to match your environment. At a minimum, you will likely need to configure:
- `garm.url` (or the individual `callbackUrl`, `metadataUrl`, `webhookUrl`)
- `ingress.host` if you are using Ingress.
- `providers` to set up at least one compute provider.
- `forges` to configure credentials for GitHub or Gitea.
3. **Install the chart:**
Once you have configured your `my-values.yaml`, install the chart using the `-f` flag to specify your custom values file.
```bash
helm install my-garm ./helm-chart -f my-values.yaml
```
## Uninstallation
To uninstall the `my-garm` deployment:
```bash
helm uninstall my-garm
```
The command removes all the Kubernetes components associated with the chart and deletes the release.

1
helm-chart/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
charts

23
helm-chart/.helmignore Normal file
View file

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

9
helm-chart/Chart.yaml Normal file
View file

@ -0,0 +1,9 @@
apiVersion: v2
name: garm
description: GARM (Github/Gitea Actions Runner Manager) Helm Chart
type: application
version: 0.1.0
appVersion: "nightly"

View file

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- $protocol := "http" -}}
{{- if .Values.ingress.tls.secretName -}}
{{- $protocol = "https" -}}
{{- end -}}
echo {{ $protocol }}://{{ .Values.ingress.host }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "garm.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "garm.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "garm.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "garm.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

View file

@ -0,0 +1,72 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "garm.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "garm.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "garm.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "garm.labels" -}}
helm.sh/chart: {{ include "garm.chart" . }}
{{ include "garm.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "garm.selectorLabels" -}}
app.kubernetes.io/name: {{ include "garm.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "garm.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "garm.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{- define "garm.admin-secret-name" -}}
{{- .Values.garm.admin.secretName | default (printf "%s-admin-credentials" (include "garm.fullname" .)) -}}
{{- end -}}
{{- define "garm.db-path" -}}
/var/lib/garm
{{- end -}}

View file

@ -0,0 +1,89 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ include "garm.fullname" . }}-init-script"
labels:
{{- include "garm.labels" . | nindent 4 }}
data:
init.sh: |-
#!/bin/sh
set -e
INIT_MARKER="{{ include "garm.db-path" . }}/.initialized"
if [ -f "$INIT_MARKER" ]; then
echo "GARM already initialized, skipping setup."
exit 0
fi
# Start GARM in the background
/bin/garm -config /etc/garm/config.toml &
GARM_PID=$!
# Wait for the server to be ready
sleep 5
# Run GARM setup
garm-cli init \
--name "{{ include "garm.fullname" . }}" \
--url "http://localhost:{{ .Values.service.port }}" \
--callback-url "{{- if .Values.garm.callbackUrl }}{{ .Values.garm.callbackUrl }}{{- else }}{{ .Values.garm.url | trimSuffix "/" }}/api/v1/callbacks{{- end }}" \
--metadata-url "{{- if .Values.garm.metadataUrl }}{{ .Values.garm.metadataUrl }}{{- else }}{{ .Values.garm.url | trimSuffix "/" }}/api/v1/metadata{{- end }}" \
--webhook-url "{{- if .Values.garm.webhookUrl }}{{ .Values.garm.webhookUrl }}{{- else }}{{ .Values.garm.url | trimSuffix "/" }}/webhooks{{- end }}" \
--username "$GARM_ADMIN_USERNAME" \
--email "$GARM_ADMIN_EMAIL" \
--password "$GARM_ADMIN_PASSWORD"
{{- if .Values.forges.gitea.credentials }}
{{- range $i, $cred := .Values.forges.gitea.credentials }}
GITEA_URL=$(cat /gitea-secrets/{{ $cred.name }}/{{ $cred.urlKey }})
GITEA_TOKEN=$(cat /gitea-secrets/{{ $cred.name }}/{{ $cred.tokenKey }})
garm-cli gitea endpoint create --api-base-url "$GITEA_URL" --base-url "$GITEA_URL" --description "{{ $cred.name }}" --name "{{ $cred.name }}"
garm-cli gitea credentials add --endpoint "{{ $cred.name }}" --auth-type pat --pat-oauth-token "$GITEA_TOKEN" --name "{{ $cred.name }}-token" --description "{{ $cred.name }} access token"
{{- end }}
{{- end }}
{{- if .Values.forges.github.credentials }}
{{- range $cred := .Values.forges.github.credentials }}
{{- if $cred.urlKey }}
GITHUB_URL=$(cat /github-secrets/{{ $cred.name }}/{{ $cred.urlKey }})
garm-cli github endpoint create \
--api-base-url "$GITHUB_URL" \
--base-url "$GITHUB_URL" \
--description "{{ $cred.name }}" \
--name "{{ $cred.name }}"
{{- end }}
{{- if eq $cred.authType "pat" }}
GITHUB_TOKEN=$(cat /github-secrets/{{ $cred.name }}/{{ $cred.tokenKey }})
garm-cli github credentials add \
--name "{{ $cred.name }}" \
{{- if $cred.urlKey }}
--endpoint "{{ $cred.name }}" \
{{- end }}
--auth-type pat \
--pat-oauth-token "$GITHUB_TOKEN"
{{- else if eq $cred.authType "app" }}
APP_ID=$(cat /github-secrets/{{ $cred.name }}/{{ $cred.appIdKey }})
INSTALL_ID=$(cat /github-secrets/{{ $cred.name }}/{{ $cred.appInstallationIdKey }})
PRIVATE_KEY_PATH="/github-secrets/{{ $cred.name }}/{{ $cred.privateKeyKey }}"
garm-cli github credentials add \
--name "{{ $cred.name }}" \
{{- if $cred.urlKey }}
--endpoint "{{ $cred.name }}" \
{{- end }}
--auth-type app \
--app-id "$APP_ID" \
--app-installation-id "$INSTALL_ID" \
--private-key-path "$PRIVATE_KEY_PATH"
{{- end }}
{{- end }}
{{- end }}
echo "GARM initialization complete."
# Stop the background GARM server
kill $GARM_PID
# Create the marker file to indicate that initialization is done
touch "$INIT_MARKER"

View file

@ -0,0 +1,17 @@
{{- /*
Create a ConfigMap for each provider defined in values.yaml
*/}}
{{- range $provider := .Values.providers }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ include "garm.fullname" $ }}-provider-{{ .name }}"
labels:
{{- include "garm.labels" $ | nindent 4 }}
data:
garm-provider-{{ .name }}.toml: |
{{- range $key, $value := .config }}
{{ $key }} = {{ $value | toToml }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,47 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ include "garm.fullname" . }}-config"
labels:
{{- include "garm.labels" . | nindent 4 }}
data:
config.toml: |-
[default]
enable_webhook_management = true
[logging]
enable_log_streamer = true
log_format = "text"
log_level = "info"
log_source = false
[metrics]
enable = true
disable_auth = false
[jwt_auth]
secret = "$GARM_JWT_SECRET"
time_to_live = "8760h"
[apiserver]
bind = "0.0.0.0"
port = {{ .Values.service.port }}
use_tls = false
[apiserver.webui]
enable = {{ .Values.garm.ui.enabled }}
[database]
backend = "sqlite3"
passphrase = "$GARM_DB_PASSPHRASE"
[database.sqlite3]
db_file = "{{ include "garm.db-path" . }}/garm.db"
{{- range .Values.providers }}
[[provider]]
name = "{{ .name }}"
provider_type = "{{ .type | default "external" }}"
description = "{{ .description }}"
[provider.external]
provider_executable = "{{ .executable }}"
config_file = "/etc/garm/provider-configs/garm-provider-{{ .name }}.toml"
{{- end }}

View file

@ -0,0 +1,166 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "garm.fullname" . }}
labels:
{{- include "garm.labels" . | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "garm.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "garm.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "garm.serviceAccountName" . }}
volumes:
- name: garm-config
emptyDir: {}
{{- if .Values.persistence.enabled }}
- name: garm-db
persistentVolumeClaim:
claimName: {{ include "garm.fullname" . }}-db
{{- end }}
- name: config-templates
configMap:
name: "{{ include "garm.fullname" . }}-config"
- name: init-script
configMap:
name: "{{ include "garm.fullname" . }}-init-script"
defaultMode: 0755
{{- range .Values.providers }}
- name: provider-config-{{ .name }}
configMap:
name: {{ include "garm.fullname" $ }}-provider-{{ .name }}
{{- end }}
{{- if .Values.forges.gitea.credentials }}
{{- range .Values.forges.gitea.credentials }}
- name: gitea-secret-{{ .name }}
secret:
secretName: {{ .secretName }}
{{- end }}
{{- end }}
{{- if .Values.forges.github.credentials }}
{{- range .Values.forges.github.credentials }}
- name: github-secret-{{ .name }}
secret:
secretName: {{ .secretName }}
{{- end }}
{{- end }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
initContainers:
- name: substitute-config
image: envsubst/envsubst
command: ["/bin/sh", "-c"]
args:
- |
envsubst < /config-templates/config.toml > /etc/garm/config.toml
env:
- name: GARM_JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ include "garm.admin-secret-name" . }}
key: {{ .Values.garm.admin.jwtSecretKey }}
- name: GARM_DB_PASSPHRASE
valueFrom:
secretKeyRef:
name: {{ include "garm.admin-secret-name" . }}
key: {{ .Values.garm.admin.dbPassphraseKey }}
volumeMounts:
- name: garm-config
mountPath: /etc/garm
- name: config-templates
mountPath: /config-templates
- name: config-init
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["/init/init.sh"]
env:
- name: GARM_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ include "garm.admin-secret-name" . }}
key: {{ .Values.garm.admin.usernameKey }}
- name: GARM_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "garm.admin-secret-name" . }}
key: {{ .Values.garm.admin.passwordKey }}
- name: GARM_ADMIN_EMAIL
valueFrom:
secretKeyRef:
name: {{ include "garm.admin-secret-name" . }}
key: {{ .Values.garm.admin.emailKey }}
volumeMounts:
- name: garm-config
mountPath: /etc/garm
{{- if .Values.persistence.enabled }}
- name: garm-db
mountPath: {{ include "garm.db-path" . }}
{{- end }}
- name: config-templates
mountPath: /config-templates
- name: init-script
mountPath: /init
{{- if .Values.forges.gitea.credentials }}
{{- range .Values.forges.gitea.credentials }}
- name: gitea-secret-{{ .name }}
mountPath: /gitea-secrets/{{ .name }}
readOnly: true
{{- end }}
{{- end }}
{{- if .Values.forges.github.credentials }}
{{- range .Values.forges.github.credentials }}
- name: github-secret-{{ .name }}
mountPath: /github-secrets/{{ .name }}
readOnly: true
{{- end }}
{{- end }}
{{- range .Values.providers }}
- name: provider-config-{{ .name }}
mountPath: "/etc/garm/provider-configs/garm-provider-{{ .name }}.toml"
subPath: "garm-provider-{{ .name }}.toml"
readOnly: true
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
protocol: TCP
volumeMounts:
- name: garm-config
mountPath: /etc/garm
{{- if .Values.persistence.enabled }}
- name: garm-db
mountPath: {{ include "garm.db-path" . }}
{{- end }}
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- range .Values.providers }}
- name: provider-config-{{ .name }}
mountPath: "/etc/garm/provider-configs/garm-provider-{{ .name }}.toml"
subPath: "garm-provider-{{ .name }}.toml"
readOnly: true
{{- end }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}

View file

@ -0,0 +1,33 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "garm.fullname" . }}
labels:
{{- include "garm.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls.secretName }}
tls:
- hosts:
- {{ .Values.ingress.host | quote }}
secretName: {{ .Values.ingress.tls.secretName }}
{{- end }}
rules:
- host: {{ .Values.ingress.host | quote }}
http:
paths:
- path: "/"
pathType: "Prefix"
backend:
service:
name: {{ include "garm.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}

View file

@ -0,0 +1,23 @@
{{- if .Values.persistence.enabled -}}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "garm.fullname" . }}-db
labels:
{{- include "garm.labels" . | nindent 4 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
{{- range .Values.persistence.accessModes }}
- {{ . }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- if .Values.persistence.storageClassName }}
storageClassName: {{ .Values.persistence.storageClassName }}
{{- end }}
{{- end }}

View file

@ -0,0 +1,31 @@
{{- if not .Values.garm.admin.secretName -}}
{{- $secretName := include "garm.admin-secret-name" . -}}
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace $secretName -}}
{{- $password := "" -}}
{{- $jwtSecret := "" -}}
{{- $dbPassphrase := "" -}}
{{- if $existingSecret -}}
{{- $password = index $existingSecret.data .Values.garm.admin.passwordKey | b64dec -}}
{{- $jwtSecret = index $existingSecret.data .Values.garm.admin.jwtSecretKey | b64dec -}}
{{- $dbPassphrase = index $existingSecret.data .Values.garm.admin.dbPassphraseKey | b64dec -}}
{{- else -}}
{{- $password = randAlphaNum 40 -}}
{{- $jwtSecret = randAlphaNum 64 -}}
{{- $dbPassphrase = randAlphaNum 32 -}}
{{- end -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}
labels:
{{- include "garm.labels" . | nindent 4 }}
stringData:
{{ .Values.garm.admin.usernameKey }}: {{ .Values.garm.admin.defaultUsername | quote }}
{{ .Values.garm.admin.passwordKey }}: {{ $password | quote }}
{{ .Values.garm.admin.emailKey }}: {{ .Values.garm.admin.defaultEmail | quote }}
{{ .Values.garm.admin.jwtSecretKey }}: {{ $jwtSecret | quote }}
{{ .Values.garm.admin.dbPassphraseKey }}: {{ $dbPassphrase | quote }}
{{- end -}}

View file

@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "garm.fullname" . }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
labels:
{{- include "garm.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "garm.selectorLabels" . | nindent 4 }}

View file

@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "garm.serviceAccountName" . }}
labels:
{{- include "garm.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

169
helm-chart/values.yaml Normal file
View file

@ -0,0 +1,169 @@
# -- GARM application configuration
garm:
# -- Enable the GARM web UI.
ui:
enabled: true
# -- GARM admin user credentials. These will be stored in a Kubernetes secret.
admin:
# -- The name of the secret containing the admin credentials.
# -- If not set, a secret will be created with a generated password.
secretName: ""
# -- The default admin username to use when generating the secret.
defaultUsername: "admin"
# -- The default admin email address to use when generating the secret.
defaultEmail: "admin@example.com"
# -- The key in the secret for the admin username.
usernameKey: "username"
# -- The key in the secret for the admin password.
passwordKey: "password"
# -- The key in the secret for the admin email.
emailKey: "email"
# -- The key in the secret for the JWT secret.
jwtSecretKey: "jwt-secret"
# -- The key in the secret for the database passphrase.
dbPassphraseKey: "db-passphrase"
# -- The base URL for the GARM service. This will be used in garm init process.
# -- You can omit this variable if URLs below are set.
url: "http://garm.example.com:9997"
# -- Specify callback URL (with correct URI path). If empty, garm.url will be used.
callbackUrl: ""
# -- Specify metadata URL (with correct URI path). If empty, garm.url will be used.
metadataUrl: ""
# -- Specify webhook URL (with correct URI path). If empty, garm.url will be used.
webhookUrl: ""
# -- Image configuration for GARM and its components.
image:
# -- GARM image repository.
repository: ghcr.io/cloudbase/garm
# -- GARM image pull policy.
pullPolicy: Always
# -- GARM image tag. Overrides the chart's appVersion.
tag: ""
# -- Overrides for the chart name.
nameOverride: ""
# -- Overrides for the full chart name.
fullnameOverride: ""
# -- ServiceAccount configuration.
serviceAccount:
# -- Specifies whether a service account should be created.
create: true
# -- Automatically mount a ServiceAccount's API credentials.
automount: true
# -- Annotations to add to the service account.
annotations: {}
# -- The name of the service account to use.
# -- If not set and create is true, a name is generated using the fullname template.
name: ""
# -- Annotations for the Pod.
podAnnotations: {}
# -- Labels for the Pod.
podLabels: {}
# -- Service configuration.
service:
# -- Kubernetes service type.
type: ClusterIP
# -- The port for the GARM service.
port: 9997
annotations: {}
# -- Ingress configuration.
ingress:
# -- Enable or disable the Ingress resource.
enabled: false
# -- The public-facing host for the Ingress resource. Required if ingress.enabled is true.
host: ""
# -- IngressClassName for the Ingress resource.
className: ""
# -- Annotations for the Ingress resource.
annotations: {}
# -- TLS configuration for the Ingress.
tls:
# -- The name of the secret containing the TLS certificate.
secretName: ""
# -- Resource requests and limits for the GARM container.
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
# -- Additional volumes to mount in the Pod.
extraVolumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
# -- Additional volume mounts for the GARM container.
extraVolumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
# -- Persistence configuration for the GARM database.
persistence:
# -- Enable or disable persistence.
enabled: true
# -- Annotations for the PVC.
annotations: {}
# -- The storage class to use for the PVC.
storageClassName: ""
# -- The access modes for the PVC.
accessModes:
- ReadWriteOnce
# -- The size of the PVC.
size: 1Gi
# -- Configuration for different git forges.
forges:
# -- Gitea server configurations.
gitea:
# -- A list of Gitea credentials. If empty, Gitea integration is not initialized.
credentials: []
# - name: "my-gitea"
# secretName: "garm-gitea-config"
# urlKey: "server-url"
# tokenKey: "access-token"
# -- GitHub server configurations.
github:
# -- A list of GitHub servers/credentials. If empty, GitHub integration is not initialized.
credentials: []
# - name: "my-github"
# secretName: "my-github-secret"
# -- If this field is empty, the default GitHub endpoint will be used.
# urlKey: ""
# -- Allowed values: 'pat' or 'app'
# authType: "pat"
# -- Specify this key only if authType is 'pat'
# tokenKey: "token"
# -- Specify values below only if authType is 'app'
# appIdKey: "app-id"
# appInstallationIdKey: "app-installation-id"
# privateKeyKey: "private-key"
# -- Configuration for different providers.
providers: []
# - name: "gcp" # Unique name for this provider
# type: "external" # Provider type
# description: "GCP provider"
# executable: "/opt/garm/providers.d/garm-provider-gcp" # Path to the executable
#
# # -- Dynamic configuration for the provider's .toml file.
# # -- You can add any keys here, and they will be added to the ConfigMap.
# config:
# project_id: "my-gcp-project"
# zone: "us-central1-a"
# network_id: "projects/my-gcp-project/global/networks/default"
# subnetwork_id: "projects/my-gcp-project/regions/us-central1/subnetworks/default"
# external_ip_access: true