feat: Add Pocket ID Helm chart with deployment, service, ingress, and backup configurations

This commit is contained in:
sha
2026-04-19 03:11:23 +03:00
parent 93538e432d
commit e0c2043b08
10 changed files with 417 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
apiVersion: v2
name: pocket-id
description: Pocket ID Helm chart
type: application
version: 0.1.0
appVersion: "2.4.0"
annotations:
version-source: github-release:pocket-id/pocket-id
version-pattern: "s|^v||"
+8
View File
@@ -0,0 +1,8 @@
{{/* PVC name to mount: existing claim if set, otherwise the chart-created one */}}
{{- define "pocket-id.pvcName" -}}
{{- if .Values.persistence.existingClaim -}}
{{ .Values.persistence.existingClaim }}
{{- else -}}
{{ .Release.Name }}-data
{{- end -}}
{{- end -}}
@@ -0,0 +1,60 @@
{{- if .Values.backup.db.enabled }}
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ .Release.Name }}-db-backup
spec:
schedule: {{ .Values.backup.db.schedule | quote }}
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: pg-dump
image: {{ .Values.backup.db.image }}
command:
- /bin/sh
- -c
- |
set -e
mkdir -p /backup
TS=$(date +%Y%m%d-%H%M%S)
pg_dump -h $PGHOST -U $DB_USER -d $DB_NAME \
| gzip > /backup/${FILE_PREFIX}-${TS}.sql.gz
find /backup -name "${FILE_PREFIX}-*.sql.gz" -mtime +$RETENTION_DAYS -delete
env:
- name: PGHOST
value: {{ .Values.backup.db.host | quote }}
- name: DB_USER
value: {{ .Values.backup.db.user | quote }}
- name: DB_NAME
value: {{ .Values.backup.db.database | quote }}
- name: FILE_PREFIX
value: {{ .Values.backup.db.filePrefix | quote }}
- name: RETENTION_DAYS
value: {{ .Values.backup.db.retentionDays | quote }}
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.existingSecret }}
key: {{ .Values.backup.db.passwordSecretKey }}
volumeMounts:
- name: backup-storage
mountPath: /backup
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
volumes:
- name: backup-storage
hostPath:
path: {{ .Values.backup.db.hostPath }}
type: DirectoryOrCreate
{{- end }}
@@ -0,0 +1,59 @@
{{- if .Values.backup.pvc.enabled }}
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ .Release.Name }}-pvc-backup
spec:
schedule: {{ .Values.backup.pvc.schedule | quote }}
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
{{- with .Values.backup.pvc.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 12 }}
{{- end }}
containers:
- name: tar-backup
image: {{ .Values.backup.pvc.image }}
command:
- /bin/sh
- -c
- |
set -e
mkdir -p /backup
TS=$(date +%Y%m%d-%H%M%S)
tar czf /backup/${FILE_PREFIX}-${TS}.tar.gz -C /data .
find /backup -name "${FILE_PREFIX}-*.tar.gz" -mtime +$RETENTION_DAYS -delete
env:
- name: FILE_PREFIX
value: {{ .Values.backup.pvc.filePrefix | quote }}
- name: RETENTION_DAYS
value: {{ .Values.backup.pvc.retentionDays | quote }}
volumeMounts:
- name: data
mountPath: /data
readOnly: true
- name: backup-storage
mountPath: /backup
resources:
requests:
memory: "32Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "500m"
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ include "pocket-id.pvcName" . }}
readOnly: true
- name: backup-storage
hostPath:
path: {{ .Values.backup.pvc.hostPath }}
type: DirectoryOrCreate
{{- end }}
+71
View File
@@ -0,0 +1,71 @@
{{- if .Values.dbInit.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-db-init
annotations:
"helm.sh/hook": post-install
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: postgres-init
image: {{ .Values.dbInit.image }}
command:
- /bin/sh
- -c
- |
set -e
until pg_isready -h $PGHOST -p $PGPORT -U $ADMIN_USER; do
echo "Waiting for PostgreSQL to be ready..."
sleep 2
done
export PGPASSWORD=$POSTGRES_ADMIN_PASSWORD
echo "Creating user $DB_USER if missing..."
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d postgres -tc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1 || \
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d postgres -c "CREATE USER $DB_USER WITH PASSWORD '${DB_USER_PASSWORD}';"
echo "Creating database $DB_NAME if missing..."
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1 || \
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d postgres -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;"
echo "Granting privileges..."
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d $DB_NAME -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;"
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d $DB_NAME -c "GRANT ALL PRIVILEGES ON SCHEMA public TO $DB_USER;"
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d $DB_NAME -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO $DB_USER;"
psql -h $PGHOST -p $PGPORT -U $ADMIN_USER -d $DB_NAME -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO $DB_USER;"
echo "Database initialization complete."
env:
- name: PGHOST
value: {{ .Values.dbInit.host | quote }}
- name: PGPORT
value: {{ .Values.dbInit.port | quote }}
- name: ADMIN_USER
value: {{ .Values.dbInit.adminUser | quote }}
- name: DB_NAME
value: {{ .Values.dbInit.database | quote }}
- name: DB_USER
value: {{ .Values.dbInit.user | quote }}
- name: POSTGRES_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.existingSecret }}
key: {{ .Values.dbInit.adminPasswordSecretKey }}
- name: DB_USER_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.existingSecret }}
key: {{ .Values.dbInit.userPasswordSecretKey }}
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
{{- end }}
+71
View File
@@ -0,0 +1,71 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
annotations:
version-source: {{ index .Chart.Annotations "version-source" }}
version-pattern: {{ index .Chart.Annotations "version-pattern" | quote }}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:v{{ .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.port }}
name: http
protocol: TCP
{{- if or .Values.env .Values.secretEnvKeys }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range .Values.secretEnvKeys }}
- name: {{ .envName }}
valueFrom:
secretKeyRef:
name: {{ $.Values.existingSecret }}
key: {{ .secretKey }}
{{- end }}
{{- end }}
{{- if .Values.existingSecret }}
envFrom:
- secretRef:
name: {{ .Values.existingSecret }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ include "pocket-id.pvcName" . }}
+27
View File
@@ -0,0 +1,27 @@
{{- range $name, $config := .Values.ingresses }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $.Release.Name }}-{{ $name }}
{{- with $config.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
rules:
- host: {{ $config.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ $.Release.Name }}
port:
number: {{ $.Values.servicePort }}
{{- with $config.tls }}
tls:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
+13
View File
@@ -0,0 +1,13 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ .Release.Name }}-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: {{ .Values.persistence.storageClass }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- end }}
+16
View File
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}
labels:
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
type: ClusterIP
selector:
app: {{ .Release.Name }}
ports:
- name: http
port: {{ .Values.servicePort }}
targetPort: http
protocol: TCP
+83
View File
@@ -0,0 +1,83 @@
# Default values for Pocket ID Helm Chart
image:
repository: ghcr.io/pocket-id/pocket-id
pullPolicy: IfNotPresent
port: 1411
# Service port exposed inside the cluster
servicePort: 80
env: {}
# APP_URL: "https://id.example.com"
# TRUST_PROXY: "true"
# Reference an existing Kubernetes Secret for envFrom
existingSecret: ""
secretEnvKeys: []
# - envName: DB_CONNECTION_STRING
# secretKey: DB_CONNECTION_STRING
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
nodeSelector: {}
tolerations: []
affinity: {}
persistence:
enabled: true
# When set, chart uses an existing PVC and does NOT create one
existingClaim: ""
storageClass: local-path
size: 5Gi
ingresses: {}
# https:
# host: id.example.com
# annotations: {}
# tls:
# - hosts:
# - id.example.com
# One-shot Job that ensures DB user/database exist in an external Postgres.
# Runs as a Helm post-install hook. Idempotent.
dbInit:
enabled: false
host: postgres-tcp.postgres.svc.cluster.local
port: 5432
adminUser: postgres
database: pocket_id
user: pocket_id
# References keys on existingSecret
adminPasswordSecretKey: POSTGRES_ADMIN_PASSWORD
userPasswordSecretKey: POCKET_ID_DB_PASSWORD
image: postgres:16-alpine
backup:
db:
enabled: false
schedule: "0 4 * * *"
retentionDays: 7
image: postgres:16-alpine
host: postgres-tcp.postgres.svc.cluster.local
user: pocket_id
database: pocket_id
passwordSecretKey: POCKET_ID_DB_PASSWORD
hostPath: /srv/backups/postgres
filePrefix: pocket_id
pvc:
enabled: false
schedule: "30 4 * * *"
retentionDays: 7
image: busybox:latest
hostPath: /srv/backups/pvc
filePrefix: pocket-id-data
# Pin the backup pod to the same node as the PVC owner (required for RWO local-path)
nodeSelector: {}