Add SOGo via Helm

This commit is contained in:
Ruben Hensen
2026-01-26 17:40:22 +01:00
parent 5dc2657524
commit b81130d02c
11 changed files with 446 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: sogo
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/rubenhensen/k8scd.git
targetRevision: HEAD
path: sogo
destination:
server: https://kubernetes.default.svc
namespace: sogo
syncPolicy:
automated:
selfHeal: true
prune: true
syncOptions:
- CreateNamespace=true
+5
View File
@@ -0,0 +1,5 @@
apiVersion: v2
name: sogo
description: Helm chart for SOGo groupware server
version: 0.1.0
appVersion: "latest"
+60
View File
@@ -0,0 +1,60 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "sogo.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "sogo.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 "sogo.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "sogo.labels" -}}
helm.sh/chart: {{ include "sogo.chart" . }}
{{ include "sogo.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "sogo.selectorLabels" -}}
app.kubernetes.io/name: {{ include "sogo.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
PostgreSQL connection URL
*/}}
{{- define "sogo.postgresqlURL" -}}
{{- $user := .Values.postgresql.username -}}
{{- $host := printf "%s-postgres-rw.%s.svc.cluster.local" (include "sogo.fullname" .) .Release.Namespace -}}
{{- $port := "5432" -}}
{{- $db := .Values.postgresql.database -}}
{{- printf "postgresql://%s:${POSTGRES_PASSWORD}@%s:%s/%s?sslmode=require" $user $host $port $db -}}
{{- end }}
+88
View File
@@ -0,0 +1,88 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "sogo.fullname" . }}-config
labels:
{{- include "sogo.labels" . | nindent 4 }}
data:
01-database.yaml: |
OCSFolderInfoURL: {{ include "sogo.postgresqlURL" . }}/sogo_folder_info
OCSSessionsFolderURL: {{ include "sogo.postgresqlURL" . }}/sogo_sessions_folder
OCSEMailAlarmsFolderURL: {{ include "sogo.postgresqlURL" . }}/sogo_alarms_folder
OCSStoreURL: {{ include "sogo.postgresqlURL" . }}/sogo_store
OCSAclURL: {{ include "sogo.postgresqlURL" . }}/sogo_acl
OCSCacheFolderURL: {{ include "sogo.postgresqlURL" . }}/sogo_cache_folder
02-mail.yaml: |
SOGoIMAPServer: {{ .Values.config.mail.imapServer }}
SOGoIMAPAclConformsToIMAPExt: YES
SOGoMailDomain: {{ .Values.config.domain }}
SOGoMailingMechanism: smtp
SOGoSMTPServer: {{ .Values.config.mail.smtpServer }}:{{ .Values.config.mail.smtpPort }}
SOGoMailSpoolPath: /var/spool/sogo
SOGoSentFolderName: Sent
SOGoTrashFolderName: Trash
SOGoDraftsFolderName: Drafts
SOGoJunkFolderName: Junk
SOGoForceExternalLoginWithEmail: YES
03-general.yaml: |
SOGoLanguage: {{ .Values.config.language }}
SOGoTimeZone: {{ .Values.config.timezone }}
SOGoSuperUsername: {{ .Values.config.adminUser }}
SOGoProfileURL: {{ include "sogo.postgresqlURL" . }}/sogo_user_profile
SOGoUserSources:
- type: sql
id: users
viewURL: {{ include "sogo.postgresqlURL" . }}/sogo_view
canAuthenticate: YES
isAddressBook: YES
userPasswordAlgorithm: none
{{- if .Values.config.modules.mail }}
SOGoMailAuxiliaryUserAccountsEnabled: YES
{{- end }}
{{- if .Values.config.modules.calendar }}
SOGoCalendarDefaultRoles:
- PublicViewer
- ConfidentialDAndTViewer
{{- end }}
04-calendar.yaml: |
{{- if .Values.config.modules.calendar }}
SOGoFirstDayOfWeek: {{ .Values.config.calendar.firstDayOfWeek }}
SOGoDayStartTime: {{ .Values.config.calendar.dayStartTime }}
SOGoDayEndTime: {{ .Values.config.calendar.dayEndTime }}
SOGoTimeFormat: {{ .Values.config.calendar.timeFormat | quote }}
SOGoCalendarEventsDefaultClassification: PUBLIC
SOGoFirstWeekOfYear: January1
{{- end }}
05-authentication.yaml: |
SOGoAuthenticationType: {{ .Values.config.mail.authenticationType }}
{{- if eq .Values.config.mail.authenticationType "IMAP" }}
SOGoIMAPServer: {{ .Values.config.mail.imapServer }}:{{ .Values.config.mail.imapPort }}
{{- end }}
06-webui.yaml: |
SOGoPageTitle: {{ .Values.config.webui.pageTitle | quote }}
SOGoLoginModule: Mail
SOGoRefreshViewCheck: every_minute
SOGoMailReloadOnArrival: YES
SOGoMailMessageCheck: every_5_minutes
SOGoMailPollingIntervals: (1, 5, 10, 20, 30, 60)
07-security.yaml: |
SOGoXSRFValidation: YES
SOGoPasswordChangeEnabled: NO
SOGoForceSSL: NO
WOUseRelativeURLs: NO
WOApplicationRedirectURL: /SOGo
08-performance.yaml: |
WOWorkersCount: {{ .Values.config.workersCount }}
WOListenQueueSize: {{ .Values.config.listenQueueSize }}
SOGoMaximumPingInterval: 3540
SOGoMaximumSyncInterval: 3540
SOGoInternalSyncInterval: 30
NGImap4DisableIMAP4Pooling: NO
SOGoMaximumMessageSizeLimit: 52428800
+64
View File
@@ -0,0 +1,64 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "sogo.fullname" . }}
labels:
{{- include "sogo.labels" . | nindent 4 }}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
{{- include "sogo.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
labels:
{{- include "sogo.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: sogo
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "sogo.fullname" . }}-postgres-credentials
key: password
volumeMounts:
- name: config
mountPath: /etc/sogo/sogo.conf.d
- name: data
mountPath: /var/spool/sogo
livenessProbe:
httpGet:
path: /SOGo
port: http
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /SOGo
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
resources:
{{- toYaml .Values.resources | nindent 10 }}
volumes:
- name: config
configMap:
name: {{ include "sogo.fullname" . }}-config
- name: data
persistentVolumeClaim:
claimName: {{ include "sogo.fullname" . }}-data
+24
View File
@@ -0,0 +1,24 @@
{{- if .Values.externalSecret.enabled }}
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ include "sogo.fullname" . }}-postgres-credentials
labels:
{{- include "sogo.labels" . | nindent 4 }}
spec:
secretStoreRef:
name: {{ .Values.externalSecret.secretStore }}
kind: ClusterSecretStore
refreshInterval: {{ .Values.externalSecret.refreshInterval }}
target:
name: {{ include "sogo.fullname" . }}-postgres-credentials
creationPolicy: Owner
template:
engineVersion: v2
data:
username: "{{ `{{ .postgres_user }}` }}"
password: "{{ `{{ .postgres_pw }}` }}"
dataFrom:
- extract:
key: {{ .Values.externalSecret.vaultPath }}
{{- end }}
+29
View File
@@ -0,0 +1,29 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "sogo.fullname" . }}
labels:
{{- include "sogo.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className }}
tls:
- hosts:
- {{ .Values.ingress.host }}
secretName: {{ .Values.ingress.tls.secretName }}
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "sogo.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}
+42
View File
@@ -0,0 +1,42 @@
{{- if .Values.postgresql.enabled }}
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: {{ include "sogo.fullname" . }}-postgres
labels:
{{- include "sogo.labels" . | nindent 4 }}
spec:
instances: {{ .Values.postgresql.instances }}
primaryUpdateStrategy: unsupervised
bootstrap:
initdb:
database: {{ .Values.postgresql.database }}
owner: {{ .Values.postgresql.username }}
secret:
name: {{ include "sogo.fullname" . }}-postgres-credentials
postInitSQL:
- CREATE EXTENSION IF NOT EXISTS pg_trgm;
storage:
storageClass: {{ .Values.postgresql.storage.storageClass }}
size: {{ .Values.postgresql.storage.size }}
postgresql:
parameters:
shared_buffers: {{ .Values.postgresql.sharedBuffers }}
max_connections: {{ .Values.postgresql.maxConnections | quote }}
log_destination: 'csvlog'
logging_collector: 'on'
log_directory: '/var/log/postgresql'
log_filename: 'postgres'
log_rotation_age: '0'
log_rotation_size: '0'
log_truncate_on_rotation: 'off'
pg_hba:
- host all all all scram-sha-256
monitoring:
enablePodMonitor: false
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
{{- if .Values.persistence.enabled }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "sogo.fullname" . }}-data
labels:
{{- include "sogo.labels" . | nindent 4 }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
storageClassName: {{ .Values.persistence.storageClass }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "sogo.fullname" . }}
labels:
{{- include "sogo.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "sogo.selectorLabels" . | nindent 4 }}
+84
View File
@@ -0,0 +1,84 @@
image:
repository: ghcr.io/sonroyaalmerol/docker-sogo
tag: latest
pullPolicy: Always
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: prod-cluster-issuer
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
host: post.hensen.io
tls:
secretName: sogo-tls
persistence:
enabled: true
storageClass: longhorn
size: 5Gi
accessMode: ReadWriteOnce
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
config:
timezone: Europe/Amsterdam
language: en
domain: hensen.io
adminUser: admin@hensen.io
workersCount: 3
listenQueueSize: 5
modules:
mail: true
calendar: true
contacts: true
tasks: true
mail:
imapServer: stalwart.stalwart.svc.cluster.local
imapPort: 993
imapEncryption: tls
smtpServer: stalwart.stalwart.svc.cluster.local
smtpPort: 587
smtpEncryption: tls
authenticationType: IMAP
calendar:
firstDayOfWeek: 1 # Monday
dayStartTime: 8
dayEndTime: 18
timeFormat: "%H:%M"
webui:
pageTitle: "Hensen Webmail"
mailReloadInterval: 300
calendarReloadInterval: 300
postgresql:
enabled: true
instances: 1
storage:
storageClass: longhorn
size: 10Gi
database: sogo
username: sogo
sharedBuffers: 256MB
maxConnections: 100
externalSecret:
enabled: true
secretStore: vault-backend
vaultPath: kv/sogo
refreshInterval: 15m