added recipya helm chart init commit

This commit is contained in:
Richard Tomik
2025-04-05 18:38:16 +02:00
parent 7cafc6a692
commit 20d661ef6f
10 changed files with 690 additions and 0 deletions

15
charts/recipya/Chart.yaml Normal file
View File

@ -0,0 +1,15 @@
apiVersion: v2
name: recipya
description: A Helm chart for Recipya recipe manager application
type: application
version: 0.0.1
appVersion: "v1.2.2"
maintainers:
- name: Richard Tomik
email: no@m.com
keywords:
- recipe-manager
- recipya
home: https://github.com/rtomik/helm-charts
sources:
- https://github.com/reaper47/recipya

122
charts/recipya/readme.md Normal file
View File

@ -0,0 +1,122 @@
# Recipya Helm Chart
A Helm chart for deploying [Recipya](https://github.com/reaper47/recipya) on Kubernetes.
## Introduction
This chart deploys Recipya recipe manager on a Kubernetes cluster using the Helm package manager.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.2.0+
- PV provisioner support in the underlying infrastructure (if persistence is needed)
## Installing the Chart
To install the chart with the release name `recipya`:
```bash
helm repo add recipya-chart https://rtomik.github.io/helm-charts
helm install recipya recipya-chart/recipya -n recipya
```
The command deploys Recipya on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation.
## Uninstalling the Chart
To uninstall/delete the `my-recipya` deployment:
```bash
helm uninstall recipya -n recipya
```
## Parameters
### Global parameters
| Name | Description | Value |
|--------------------------|--------------------------------------|-----------------|
| `image.repository` | Recipya image repository | `reaper99/recipya` |
| `image.tag` | Recipya image tag | `v1.2.2` |
| `image.pullPolicy` | Recipya image pull policy | `IfNotPresent` |
| `replicaCount` | Number of Recipya replicas | `1` |
| `revisionHistoryLimit` | Number of revisions to keep | `3` |
### Security parameters
| Name | Description | Value |
|-----------------------------------------|--------------------------------------------------|-----------|
| `podSecurityContext.fsGroup` | Group ID for the Recipya container | `1000` |
| `containerSecurityContext.runAsUser` | User ID for the Recipya container | `1000` |
| `containerSecurityContext.runAsGroup` | Group ID for the Recipya container | `1000` |
| `containerSecurityContext.runAsNonRoot` | Run containers as non-root | `true` |
### Recipya configuration parameters
| Name | Description | Value |
|-----------------------------------------|-------------------------------------------------------|----------------|
| `config.server.port` | Server port | `8078` |
| `config.server.autologin` | Whether to login automatically | `false` |
| `config.server.is_demo` | Whether the app is a demo version | `false` |
| `config.server.is_prod` | Whether the app is in production | `false` |
| `config.server.no_signups` | Whether to disable user account registrations | `false` |
| `config.server.url` | Base URL for the application | `http://0.0.0.0` |
| `config.email.address` | The email address for SendGrid | `""` |
| `config.email.sendgrid` | SendGrid API key | `""` |
| `config.documentIntelligence.endpoint` | Azure Document Intelligence endpoint | `""` |
| `config.documentIntelligence.key` | Azure Document Intelligence key | `""` |
### Service parameters
| Name | Description | Value |
|--------------------------|--------------------------------------------------|-------------|
| `service.type` | Recipya service type | `ClusterIP` |
| `service.port` | Recipya service port | `8078` |
### Ingress parameters
| Name | Description | Value |
|--------------------------|--------------------------------------------------|-------------|
| `ingress.enabled` | Enable ingress controller resource | `false` |
| `ingress.className` | IngressClass that will be used | `""` |
| `ingress.hosts[0].host` | Default host for the ingress resource | `chart-example.local` |
| `ingress.tls` | Create TLS Secret | `[]` |
### Persistence parameters
| Name | Description | Value |
|--------------------------------------|------------------------------------------|-----------|
| `persistence.enabled` | Enable persistence using PVC | `true` |
| `persistence.accessMode` | PVC Access Mode | `ReadWriteOnce` |
| `persistence.size` | PVC Storage Request | `1Gi` |
| `persistence.storageClass` | Storage class of backing PVC | `""` |
### Resource parameters
| Name | Description | Value |
|--------------------------|------------------------------------------|-----------|
| `resources.limits.cpu` | CPU limit | `500m` |
| `resources.limits.memory`| Memory limit | `512Mi` |
| `resources.requests.cpu` | CPU request | `100m` |
| `resources.requests.memory` | Memory request | `128Mi` |
## Using Existing Secrets
If you want to use existing secrets for sensitive data:
```yaml
config:
email:
existingSecret: "my-email-secret"
addressKey: "email"
sendgridKey: "sendgrid"
documentIntelligence:
existingSecret: "my-di-secret"
endpointKey: "di_endpoint"
keyKey: "di_key"
```
## Configuration
See the [Recipya documentation](https://recipes.musicavis.ca/docs/installation/docker/#environment-variables) for details on all available configuration options.

View File

@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "recipya.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 "recipya.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 "recipya.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "recipya.labels" -}}
helm.sh/chart: {{ include "recipya.chart" . }}
{{ include "recipya.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "recipya.selectorLabels" -}}
app.kubernetes.io/name: {{ include "recipya.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "recipya.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "recipya.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,77 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "donetick.fullname" . }}-configmap
labels:
{{- include "donetick.labels" . | nindent 4 }}
data:
selfhosted.yaml: |
name: {{ .Values.config.name | quote }}
is_done_tick_dot_com: {{ .Values.config.is_done_tick_dot_com }}
is_user_creation_disabled: {{ .Values.config.is_user_creation_disabled }}
telegram:
token: {{ .Values.config.telegram.token | default "" | quote }}
pushover:
token: {{ .Values.config.pushover.token | default "" | quote }}
database:
type: {{ .Values.config.database.type | default "sqlite" | quote }}
migration: {{ .Values.config.database.migration }}
{{- if .Values.config.database.migration_skip }}
migration_skip: {{ .Values.config.database.migration_skip }}
{{- end }}
{{- if .Values.config.database.migration_retry }}
migration_retry: {{ .Values.config.database.migration_retry }}
{{- end }}
{{- if eq .Values.config.database.type "postgres" }}
{{- if not .Values.config.database.existingSecret }}
host: {{ .Values.config.database.host | quote }}
port: {{ .Values.config.database.port }}
user: {{ .Values.config.database.user | quote }}
password: {{ .Values.config.database.password | quote }}
name: {{ .Values.config.database.name | quote }}
{{- else }}
# Database credentials will be injected via environment variables from Secret
{{- end }}
{{- end }}
jwt:
{{- if .Values.config.jwt.existingSecret }}
# Secret will be injected from Secret
{{- else }}
secret: {{ .Values.config.jwt.secret | quote }}
{{- end }}
session_time: {{ .Values.config.jwt.session_time | quote }}
max_refresh: {{ .Values.config.jwt.max_refresh | quote }}
server:
port: {{ .Values.config.server.port }}
read_timeout: {{ .Values.config.server.read_timeout | quote }}
write_timeout: {{ .Values.config.server.write_timeout | quote }}
rate_period: {{ .Values.config.server.rate_period | quote }}
rate_limit: {{ .Values.config.server.rate_limit }}
cors_allow_origins:
{{- range .Values.config.server.cors_allow_origins }}
- {{ . | quote }}
{{- end }}
serve_frontend: {{ .Values.config.server.serve_frontend }}
scheduler_jobs:
due_job: {{ .Values.config.scheduler_jobs.due_job | quote }}
overdue_job: {{ .Values.config.scheduler_jobs.overdue_job | quote }}
pre_due_job: {{ .Values.config.scheduler_jobs.pre_due_job | quote }}
email:
host: {{ .Values.config.email.host | default "" | quote }}
port: {{ .Values.config.email.port | default "" | quote }}
key: {{ .Values.config.email.key | default "" | quote }}
email: {{ .Values.config.email.email | default "" | quote }}
appHost: {{ .Values.config.email.appHost | default "" | quote }}
oauth2:
{{- if .Values.config.oauth2.existingSecret }}
client_id: $DT_OAUTH2_CLIENT_ID
client_secret: $DT_OAUTH2_CLIENT_SECRET
{{- else }}
client_id: {{ .Values.config.oauth2.client_id | default "" | quote }}
client_secret: {{ .Values.config.oauth2.client_secret | default "" | quote }}
{{- end }}
auth_url: {{ .Values.config.oauth2.auth_url | default "" | quote }}
token_url: {{ .Values.config.oauth2.token_url | default "" | quote }}
user_info_url: {{ .Values.config.oauth2.user_info_url | default "" | quote }}
redirect_url: {{ .Values.config.oauth2.redirect_url | default "" | quote }}
name: {{ .Values.config.oauth2.name | default "" | quote }}

View File

@ -0,0 +1,179 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "recipya.fullname" . }}
labels:
{{- include "recipya.labels" . | nindent 4 }}
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
spec:
replicas: {{ .Values.replicaCount }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
{{- include "recipya.selectorLabels" . | nindent 6 }}
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
template:
metadata:
labels:
{{- include "recipya.selectorLabels" . | nindent 8 }}
annotations:
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.containerSecurityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.startupArgs }}
args:
{{- range .Values.startupArgs }}
- {{ . | quote }}
{{- end }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.config.server.port }}
protocol: TCP
{{- if .Values.probes.liveness.enabled }}
livenessProbe:
httpGet:
path: {{ .Values.probes.liveness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.liveness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.liveness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.liveness.failureThreshold }}
successThreshold: {{ .Values.probes.liveness.successThreshold }}
{{- end }}
{{- if .Values.probes.readiness.enabled }}
readinessProbe:
httpGet:
path: {{ .Values.probes.readiness.path }}
port: http
initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.readiness.periodSeconds }}
timeoutSeconds: {{ .Values.probes.readiness.timeoutSeconds }}
failureThreshold: {{ .Values.probes.readiness.failureThreshold }}
successThreshold: {{ .Values.probes.readiness.successThreshold }}
{{- end }}
env:
- name: RECIPYA_SERVER_PORT
value: {{ .Values.config.server.port | quote }}
- name: RECIPYA_SERVER_URL
value: {{ .Values.config.server.url | quote }}
- name: RECIPYA_SERVER_AUTOLOGIN
value: {{ .Values.config.server.autologin | quote }}
- name: RECIPYA_SERVER_IS_DEMO
value: {{ .Values.config.server.is_demo | quote }}
- name: RECIPYA_SERVER_IS_PROD
value: {{ .Values.config.server.is_prod | quote }}
- name: RECIPYA_SERVER_NO_SIGNUPS
value: {{ .Values.config.server.no_signups | quote }}
{{- if .Values.config.email.existingSecret }}
- name: RECIPYA_EMAIL
valueFrom:
secretKeyRef:
name: {{ .Values.config.email.existingSecret }}
key: {{ .Values.config.email.addressKey }}
- name: RECIPYA_EMAIL_SENDGRID
valueFrom:
secretKeyRef:
name: {{ .Values.config.email.existingSecret }}
key: {{ .Values.config.email.sendgridKey }}
{{- else }}
- name: RECIPYA_EMAIL
valueFrom:
secretKeyRef:
name: {{ include "recipya.fullname" . }}-secrets
key: {{ .Values.config.email.addressKey }}
- name: RECIPYA_EMAIL_SENDGRID
valueFrom:
secretKeyRef:
name: {{ include "recipya.fullname" . }}-secrets
key: {{ .Values.config.email.sendgridKey }}
{{- end }}
{{- if .Values.config.documentIntelligence.existingSecret }}
- name: RECIPYA_DI_ENDPOINT
valueFrom:
secretKeyRef:
name: {{ .Values.config.documentIntelligence.existingSecret }}
key: {{ .Values.config.documentIntelligence.endpointKey }}
- name: RECIPYA_DI_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.config.documentIntelligence.existingSecret }}
key: {{ .Values.config.documentIntelligence.keyKey }}
{{- else }}
- name: RECIPYA_DI_ENDPOINT
valueFrom:
secretKeyRef:
name: {{ include "recipya.fullname" . }}-secrets
key: {{ .Values.config.documentIntelligence.endpointKey }}
- name: RECIPYA_DI_KEY
valueFrom:
secretKeyRef:
name: {{ include "recipya.fullname" . }}-secrets
key: {{ .Values.config.documentIntelligence.keyKey }}
{{- end }}
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /home/recipya/.config/Recipya
{{- if not .Values.containerSecurityContext.readOnlyRootFilesystem }}
- name: tmp
mountPath: /tmp
{{- end }}
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ include "recipya.fullname" . }}-data
{{- if not .Values.containerSecurityContext.readOnlyRootFilesystem }}
- name: tmp
emptyDir: {}
{{- end }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

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

View File

@ -0,0 +1,21 @@
{{- if .Values.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "recipya.fullname" . }}-data
labels:
{{- include "recipya.labels" . | nindent 4 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- end }}

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ include "recipya.fullname" . }}-secrets
labels:
{{- include "recipya.labels" . | nindent 4 }}
type: Opaque
data:
{{- if not .Values.config.email.existingSecret }}
{{ .Values.config.email.addressKey }}: {{ .Values.config.email.address | b64enc }}
{{ .Values.config.email.sendgridKey }}: {{ .Values.config.email.sendgrid | b64enc }}
{{- end }}
{{- if not .Values.config.documentIntelligence.existingSecret }}
{{ .Values.config.documentIntelligence.endpointKey }}: {{ .Values.config.documentIntelligence.endpoint | b64enc }}
{{ .Values.config.documentIntelligence.keyKey }}: {{ .Values.config.documentIntelligence.key | b64enc }}
{{- end }}

View File

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

139
charts/recipya/values.yaml Normal file
View File

@ -0,0 +1,139 @@
# Default values for recipya.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
revisionHistoryLimit: 3
image:
repository: reaper99/recipya
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "v1.2.2"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# Security context for the pod
podSecurityContext:
fsGroup: 1000
# Security context for the container
containerSecurityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
# Service configuration
service:
type: ClusterIP
port: 8078
# Ingress configuration
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
# Persistent volume claim
persistence:
enabled: true
accessMode: ReadWriteOnce
size: 1Gi
# storageClass: ""
annotations: {}
# Resource limits and requests
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
# Node selector
nodeSelector: {}
# Tolerations
tolerations: []
# Affinity
affinity: {}
# Additional pod annotations
podAnnotations: {}
# Startup arguments
startupArgs: []
# Additional environment variables
env: []
# Extra environment variables
extraEnv: []
# Extra volume mounts
extraVolumeMounts: []
# Extra volumes
extraVolumes: []
# Probes configuration
probes:
liveness:
enabled: true
path: /health
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readiness:
enabled: true
path: /health
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
# Recipya configuration
config:
email:
address: ""
sendgrid: ""
existingSecret: ""
addressKey: "email"
sendgridKey: "sendgrid"
documentIntelligence:
endpoint: ""
key: ""
existingSecret: ""
endpointKey: "di_endpoint"
keyKey: "di_key"
server:
port: 8078
autologin: false
is_demo: false
is_prod: false
no_signups: false
url: "http://0.0.0.0"