feat(helm): complete chart normalization with ConfigMap, HPA, and OCI migration
- Added debug mode, structured ConfigMap pattern, and README to all charts - Migrated all flat-structure charts to hierarchical values under chartname key - Fixed templates to use correct hierarchical paths - Renamed helm-rustical key to rustical, added HPA support - Fixed ingress YAML parsing (oxicloud), nested env vars (rustical) - Pushed all normalized charts to OCI registry as 1.0.0+ and updated ArgoCD apps
This commit is contained in:
parent
d0f40c0967
commit
1fd2bfef3d
71 changed files with 2150 additions and 965 deletions
|
|
@ -2,7 +2,7 @@ apiVersion: v2
|
|||
name: helm-rustical
|
||||
description: A Helm chart for Rustical WebDAV server
|
||||
type: application
|
||||
version: 0.3.0
|
||||
version: 1.1.1
|
||||
appVersion: 0.14.1
|
||||
annotations:
|
||||
artifacthub.io/images: "- name: rustical\n image: ghcr.io/lennart-k/rustical:0.14.1\n"
|
||||
|
|
|
|||
115
k8s/charts/helm-rustical/README.md
Normal file
115
k8s/charts/helm-rustical/README.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# helm-rustical
|
||||
|
||||
A Helm chart for Rustical WebDAV server.
|
||||
|
||||
## TL;DR
|
||||
|
||||
```bash
|
||||
helm install helm-rustical oci://git.roboces.dev/catalin/fukuops/helm-rustical --version 1.1.0 -n apps-roboces
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.19+
|
||||
- Helm 3+
|
||||
- A NFS storage class (default: `truenas-nfs-csi`)
|
||||
- An existing `Secret` containing:
|
||||
- `RUSTICAL_PASSWORD` - Password for WebDAV access
|
||||
|
||||
## Configuration
|
||||
|
||||
All values are nested under the `rustical:` key. Example:
|
||||
|
||||
```yaml
|
||||
rustical:
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 1
|
||||
maxReplicas: 3
|
||||
targetCPUUtilizationPercentage: 80
|
||||
service:
|
||||
type: LoadBalancer
|
||||
port: 8001
|
||||
config:
|
||||
oidc.name: Authentik
|
||||
oidc.issuer: https://auth.example.com/application/o/rustical/
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "truenas-nfs-csi"
|
||||
size: 50Gi
|
||||
secret:
|
||||
existingSecretName: rustical
|
||||
```
|
||||
|
||||
## Values Reference
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| `rustical.replicaCount` | int | `1` | Number of replicas (when autoscaling disabled) |
|
||||
| `rustical.image.repository` | string | `ghcr.io/lennart-k/rustical` | Image repository |
|
||||
| `rustical.image.pullpolicy` | string | `Always` | Image pull policy |
|
||||
| `rustical.image.tag` | string | `.Chart.AppVersion` | Image tag |
|
||||
| `rustical.service.type` | string | `ClusterIP` | Service type |
|
||||
| `rustical.service.port` | int | `4000` | Service port |
|
||||
| `rustical.service.targetPort` | int | `4000` | Container port |
|
||||
| `rustical.ingress.enabled` | bool | `false` | Enable ingress |
|
||||
| `rustical.autoscaling.enabled` | bool | `false` | Enable HPA |
|
||||
| `rustical.autoscaling.minReplicas` | int | `1` | Minimum replicas |
|
||||
| `rustical.autoscaling.maxReplicas` | int | `3` | Maximum replicas |
|
||||
| `rustical.autoscaling.targetCPUUtilizationPercentage` | int | `80` | Target CPU utilization |
|
||||
| `rustical.autoscaling.targetMemoryUtilizationPercentage` | int | `80` | Target memory utilization |
|
||||
| `rustical.persistence.enabled` | bool | `true` | Enable persistence |
|
||||
| `rustical.persistence.storageClass` | string | `truenas-nfs-csi` | Storage class |
|
||||
| `rustical.persistence.accessMode` | string | `ReadWriteMany` | Access mode |
|
||||
| `rustical.persistence.size` | string | `50Gi` | PVC size |
|
||||
| `rustical.secret.existingSecretName` | string | `rustical` | Existing secret name |
|
||||
| `rustical.config` | object | `{}` | Config key-value pairs mapped to env vars |
|
||||
| `rustical.debug.enabled` | bool | `false` | Enable debug mode (adds init container for troubleshooting) |
|
||||
| `rustical.resources` | object | `{}` | Container resources |
|
||||
| `rustical.livenessProbe` | object | (see values.yaml) | Liveness probe |
|
||||
| `rustical.readinessProbe` | object | (see values.yaml) | Readiness probe |
|
||||
|
||||
## ConfigMap
|
||||
|
||||
The `config:` section creates a ConfigMap that maps keys to environment variables. Keys are uppercased.
|
||||
|
||||
## Persistence
|
||||
|
||||
The chart creates a PVC named `rustical-data`. The PVC uses the `truenas-nfs-csi` storage class by default with `ReadWriteMany` access mode.
|
||||
|
||||
## Secret Management
|
||||
|
||||
The chart looks for an existing `Secret` with the name specified in `rustical.secret.existingSecretName`. Required secret keys:
|
||||
- `RUSTICAL_PASSWORD` - Password for WebDAV access
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug mode to troubleshoot issues by adding an init container with a shell:
|
||||
|
||||
```yaml
|
||||
rustical:
|
||||
debug:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
This adds an `alpine:3.19` init container with `sleep infinity` that mounts all volumes and inherits env vars. You can exec into it to inspect the environment:
|
||||
|
||||
```bash
|
||||
kubectl exec -it <pod-name> -c debug -- sh
|
||||
```
|
||||
|
||||
When debug mode is enabled, liveness and readiness probes are disabled to prevent restarts.
|
||||
|
||||
### Pod not starting
|
||||
|
||||
```bash
|
||||
kubectl get pvc -n apps-roboces -l app.kubernetes.io/name=helm-rustical
|
||||
```
|
||||
|
||||
### Check logs
|
||||
|
||||
```bash
|
||||
kubectl logs helm-rustical-0 -n apps-roboces
|
||||
```
|
||||
13
k8s/charts/helm-rustical/templates/configmap.yaml
Normal file
13
k8s/charts/helm-rustical/templates/configmap.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{{- if .Values.rustical.config }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "rustical.fullname" . }}-config
|
||||
labels:
|
||||
{{- include "rustical.labels" . | nindent 4 }}
|
||||
data:
|
||||
{{- range $key, $value := .Values.rustical.config }}
|
||||
{{- $envKey := printf "RUSTICAL_%s" ($key | upper | replace "." "__" | replace "-" "_") }}
|
||||
{{ $envKey }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
36
k8s/charts/helm-rustical/templates/hpa.yaml
Normal file
36
k8s/charts/helm-rustical/templates/hpa.yaml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{{- if .Values.rustical.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "rustical.fullname" . }}
|
||||
labels:
|
||||
{{- include "rustical.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
name: {{ include "rustical.fullname" . }}
|
||||
{{- if .Values.rustical.autoscaling.minReplicas }}
|
||||
minReplicas: {{ .Values.rustical.autoscaling.minReplicas }}
|
||||
{{- end }}
|
||||
{{- if .Values.rustical.autoscaling.maxReplicas }}
|
||||
maxReplicas: {{ .Values.rustical.autoscaling.maxReplicas }}
|
||||
{{- end }}
|
||||
metrics:
|
||||
{{- if .Values.rustical.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.rustical.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.rustical.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.rustical.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
{{- if .Values.ingress.enabled -}}
|
||||
{{- if .Values.rustical.ingress.enabled -}}
|
||||
{{- $fullName := include "rustical.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- $svcPort := .Values.rustical.service.port -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "rustical.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
{{- with .Values.rustical.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- if .Values.rustical.ingress.className }}
|
||||
ingressClassName: {{ .Values.rustical.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
{{- if .Values.rustical.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
{{- range .Values.rustical.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
|
|
@ -26,7 +26,7 @@ spec:
|
|||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
{{- range .Values.rustical.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ metadata:
|
|||
labels:
|
||||
{{- include "rustical.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
type: {{ .Values.rustical.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: {{ .Values.service.targetPort }}
|
||||
- port: {{ .Values.rustical.service.port }}
|
||||
targetPort: {{ .Values.rustical.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
|
|
|
|||
|
|
@ -6,40 +6,35 @@ metadata:
|
|||
{{- include "rustical.labels" . | nindent 4 }}
|
||||
spec:
|
||||
serviceName: {{ include "rustical.fullname" . }}-headless
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- if not .Values.rustical.autoscaling.enabled }}
|
||||
replicas: {{ .Values.rustical.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "rustical.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- with .Values.rustical.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "rustical.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with .Values.rustical.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- if .Values.debug.enabled }}
|
||||
{{- toYaml .Values.rustical.podSecurityContext | nindent 8 }}
|
||||
{{- if .Values.rustical.debug.enabled }}
|
||||
initContainers:
|
||||
- name: debug
|
||||
image: alpine:3.19
|
||||
command: ["sleep", "infinity"]
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ .Values.secret.existingSecretName }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
name: {{ .Values.rustical.secret.existingSecretName }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/rustical
|
||||
|
|
@ -53,67 +48,64 @@ spec:
|
|||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullpolicy }}
|
||||
{{- toYaml .Values.rustical.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.rustical.image.repository }}:{{ .Values.rustical.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.rustical.image.pullpolicy }}
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "rustical.fullname" . }}-config
|
||||
- secretRef:
|
||||
name: {{ .Values.secret.existingSecretName | default (include "rustical.fullname" .) }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
name: {{ .Values.rustical.secret.existingSecretName | default (include "rustical.fullname" .) }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 4000
|
||||
protocol: TCP
|
||||
{{- if not .Values.debug.enabled }}
|
||||
{{- if not .Values.rustical.debug.enabled }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||
{{- toYaml .Values.rustical.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.readinessProbe | nindent 12 }}
|
||||
{{- toYaml .Values.rustical.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- toYaml .Values.rustical.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/rustical
|
||||
{{- if .Values.persistence.existingClaim }}
|
||||
{{- if .Values.rustical.persistence.existingClaim }}
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim }}
|
||||
claimName: {{ .Values.rustical.persistence.existingClaim }}
|
||||
{{- end }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
{{- with .Values.rustical.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
{{- with .Values.rustical.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
{{- with .Values.rustical.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
restartPolicy: Always
|
||||
automountServiceAccountToken: false
|
||||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||
{{- if and .Values.rustical.persistence.enabled (not .Values.rustical.persistence.existingClaim) }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
{{- if eq "-" .Values.persistence.storageClass }}
|
||||
- {{ .Values.rustical.persistence.accessMode }}
|
||||
{{- if .Values.rustical.persistence.storageClass }}
|
||||
{{- if eq "-" .Values.rustical.persistence.storageClass }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||
storageClassName: {{ .Values.rustical.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size }}
|
||||
storage: {{ .Values.rustical.persistence.size }}
|
||||
{{- end }}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,67 @@
|
|||
# Configuration is managed in k8s/argo-apps/rustical.yaml
|
||||
replicaCount: 1
|
||||
rustical:
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/lennart-k/rustical
|
||||
pullpolicy: Always
|
||||
tag: ""
|
||||
image:
|
||||
repository: ghcr.io/lennart-k/rustical
|
||||
pullpolicy: Always
|
||||
tag: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
podAnnotations: {}
|
||||
podSecurityContext: {}
|
||||
securityContext: {}
|
||||
imagePullSecrets: []
|
||||
podAnnotations: {}
|
||||
podSecurityContext: {}
|
||||
securityContext: {}
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 4000
|
||||
targetPort: 4000
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "truenas-nfs-csi"
|
||||
accessMode: ReadWriteMany
|
||||
size: 50Gi
|
||||
existingClaim: ""
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
|
||||
resources: {}
|
||||
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 4000
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 15
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
periodSeconds: 10
|
||||
targetPort: 4000
|
||||
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 4000
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 2
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
periodSeconds: 10
|
||||
ingress:
|
||||
enabled: false
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: "truenas-nfs-csi"
|
||||
accessMode: ReadWriteMany
|
||||
size: 50Gi
|
||||
existingClaim: ""
|
||||
|
||||
env: {}
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 3
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
secret:
|
||||
enabled: true
|
||||
existingSecretName: "rustical"
|
||||
resources: {}
|
||||
|
||||
debug:
|
||||
enabled: false
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 4000
|
||||
initialDelaySeconds: 30
|
||||
timeoutSeconds: 15
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
periodSeconds: 10
|
||||
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 4000
|
||||
initialDelaySeconds: 15
|
||||
timeoutSeconds: 2
|
||||
successThreshold: 1
|
||||
failureThreshold: 3
|
||||
periodSeconds: 10
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
config: {}
|
||||
|
||||
secret:
|
||||
enabled: true
|
||||
existingSecretName: "rustical"
|
||||
|
||||
debug:
|
||||
enabled: false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue