feat: add v0.0.1

This commit is contained in:
Loïc Kalbermatter 2024-06-10 11:09:21 +02:00
commit b6445fb67e
Signed by: PulseDev
GPG Key ID: 0516267FEC58F5F3
16 changed files with 856 additions and 0 deletions

23
.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/

11
Chart.yaml Normal file
View File

@ -0,0 +1,11 @@
apiVersion: v2
name: stalwart-mail
description: Helm Chart for Stalwart Mail Server - Secure & Modern All-in-One Mail Server (IMAP, JMAP, SMTP)
icon: https://stalw.art/home/apple-touch-icon.png
type: application
version: 0.0.1
# renovate: image=docker.io/stalwartlabs/mail-server
appVersion: '0.8.1'
maintainers:
- email: loic.kalbermatter@pulseflow.ch
name: Loic Kalbermatter

139
README.md Normal file
View File

@ -0,0 +1,139 @@
# stalwart-mail
![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.8.1](https://img.shields.io/badge/AppVersion-0.8.1-informational?style=flat-square)
Helm Chart for Stalwart Mail Server - Secure & Modern All-in-One Mail Server (IMAP, JMAP, SMTP)
## Maintainers
| Name | Email | Url |
| ---- | ------ | --- |
| Loic Kalbermatter | <loic.kalbermatter@pulseflow.ch> | |
## Values
### DKIM
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| config.auth.dkim.sign | list | `[{"if":"listener != 'smtp'","then":"['rsa', 'ed25519']"},{"else":false}]` | auth rule for signing with dkim |
| config.auth.dkim.verify | string | `"relaxed"` | verify of dkim signature (relaxed, strict, disable) |
### Authentification
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| config.authentication.fallback-admin.secret | string | `"%{env:FALLBACK_ADMIN_SECRET}%"` | password for fallback authentfication (use env for store in secrets of kubernetes) |
| config.authentication.fallback-admin.user | string | `"admin"` | username for fallback authentfication |
| secrets.env.FALLBACK_ADMIN_SECRET | string | `"supersecret"` | password for fallback authentfication (env) |
### Other Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| affinity | object | `{}` | |
| autoscaling.enabled | bool | `false` | |
| autoscaling.maxReplicas | int | `100` | |
| autoscaling.minReplicas | int | `1` | |
| autoscaling.targetCPUUtilizationPercentage | int | `80` | |
| certificate.certmanager.dnsNames[0] | string | `"chart-example.local"` | |
| certificate.certmanager.enabled | bool | `true` | |
| certificate.certmanager.issuerRef.group | string | `"cert-manager.io"` | |
| certificate.certmanager.issuerRef.kind | string | `"ClusterIssuer"` | |
| certificate.certmanager.issuerRef.name | string | `"letsencrypt-prod"` | |
| certificate.secretName | string | `nil` | not needed if certmanager is used |
| config.directory.internal.store | string | `"rocksdb"` | |
| config.directory.internal.type | string | `"internal"` | |
| config.server.listener.https.bind[0] | string | `"[::]:80"` | |
| config.server.listener.https.protocol | string | `"http"` | |
| config.server.listener.https.tls.implicit | bool | `true` | |
| config.server.listener.imap.bind[0] | string | `"[::]:143"` | |
| config.server.listener.imap.protocol | string | `"imap"` | |
| config.server.listener.imaptls.bind[0] | string | `"[::]:993"` | |
| config.server.listener.imaptls.protocol | string | `"imap"` | |
| config.server.listener.imaptls.tls.implicit | bool | `true` | |
| config.server.listener.sieve.bind[0] | string | `"[::]:4190"` | |
| config.server.listener.sieve.protocol | string | `"managesieve"` | |
| config.server.listener.smtp.bind[0] | string | `"[::]:25"` | |
| config.server.listener.smtp.protocol | string | `"smtp"` | |
| config.server.listener.submission.bind[0] | string | `"[::]:587"` | |
| config.server.listener.submission.protocol | string | `"smtp"` | |
| config.server.listener.submissions.bind[0] | string | `"[::]:465"` | |
| config.server.listener.submissions.protocol | string | `"smtp"` | |
| config.server.listener.submissions.tls.implicit | bool | `true` | |
| config.server.run-as.group | string | `"stalwart-mail"` | server run-as group |
| config.server.run-as.user | string | `"stalwart-mail"` | server run-as user |
| config.storage.blob | string | `"rocksdb"` | |
| config.storage.data | string | `"rocksdb"` | |
| config.storage.directory | string | `"internal"` | |
| config.storage.fts | string | `"rocksdb"` | |
| config.storage.lookup | string | `"rocksdb"` | |
| config.store.rocksdb.compression | string | `"lz4"` | |
| config.store.rocksdb.path | string | `"/data"` | |
| config.store.rocksdb.type | string | `"rocksdb"` | |
| config.tracer.otel.enable | bool | `false` | |
| config.tracer.otel.endpoint | string | `"https://127.0.0.1/otel"` | |
| config.tracer.otel.headers | list | `[]` | headers for usage with http (e.g. 'Authorization: <place_auth_here>') |
| config.tracer.otel.level | string | `"info"` | |
| config.tracer.otel.transport | string | `"grpc"` | grpc or http |
| config.tracer.otel.type | string | `"open-telemetry"` | |
| config.tracer.stdout.ansi | bool | `false` | |
| config.tracer.stdout.enable | bool | `true` | |
| config.tracer.stdout.level | string | `"info"` | |
| config.tracer.stdout.type | string | `"stdout"` | |
| env | list | `[]` | |
| fullnameOverride | string | `""` | |
| global.image.pullPolicy | string | `nil` | if set it will overwrite all pullPolicy |
| global.image.registry | string | `nil` | if set it will overwrite all registry entries |
| image.pullPolicy | string | `"IfNotPresent"` | |
| image.registry | string | `"docker.io"` | |
| image.repository | string | `"stalwartlabs/mail-server"` | |
| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. |
| imagePullSecrets | list | `[]` | |
| ingress.annotations | object | `{}` | |
| ingress.className | string | `""` | |
| ingress.enabled | bool | `false` | |
| ingress.hosts[0].host | string | `"chart-example.local"` | |
| ingress.hosts[0].paths[0].path | string | `"/"` | |
| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | |
| ingress.tls | list | `[]` | |
| nameOverride | string | `""` | |
| nodeSelector | object | `{}` | |
| persistence.accessMode | string | `"ReadWriteOnce"` | accessMode |
| persistence.annotations | object | `{}` | |
| persistence.enabled | bool | `true` | Enable persistence using Persistent Volume Claims ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ |
| persistence.existingClaim | string | `nil` | A manually managed Persistent Volume and Claim Requires persistence.enabled: true If defined, PVC must be created manually before volume will be bound |
| persistence.hostPath | string | `nil` | Do not create an PVC, direct use hostPath in Pod |
| persistence.size | string | `"10Gi"` | size |
| persistence.storageClass | string | `nil` | Persistent Volume Storage Class If defined, storageClassName: <storageClass> If set to "-", storageClassName: "", which disables dynamic provisioning If undefined (the default) or set to null, no storageClassName spec is set, choosing the default provisioner. (gp2 on AWS, standard on GKE, AWS & OpenStack) |
| podAnnotations | object | `{}` | |
| podLabels | object | `{}` | |
| podSecurityContext | object | `{}` | |
| replicaCount | int | `1` | |
| resources | object | `{}` | |
| securityContext | object | `{}` | |
| service.annotations | object | `{}` | |
| service.ipFamilies[0] | string | `"IPv4"` | |
| service.ipFamilyPolicy | string | `"SingleStack"` | other option is RequireDualStack |
| service.ports.http | int | `80` | |
| service.ports.imap | int | `143` | |
| service.ports.imaps | int | `993` | |
| service.ports.sieve | int | `4190` | |
| service.ports.smtp | int | `25` | |
| service.ports.smtp-submission | int | `587` | |
| service.ports.smtps | int | `465` | |
| service.type | string | `"ClusterIP"` | |
| serviceAccount.annotations | object | `{}` | |
| serviceAccount.automount | bool | `true` | |
| serviceAccount.create | bool | `false` | |
| serviceAccount.name | string | `""` | |
| tolerations | list | `[]` | |
| traefik.enabled | bool | `false` | |
| traefik.ports.http | string | `"websecure"` | |
| traefik.ports.imaps | string | `"imaps"` | |
| traefik.ports.smtps | string | `"smtps"` | |
| volumeMounts | list | `[]` | |
| volumes | list | `[]` | |
----------------------------------------------
Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1)

22
templates/NOTES.txt Normal file
View File

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "stalwart-mail.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 the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "stalwart-mail.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "stalwart-mail.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 "stalwart-mail.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 }}

62
templates/_helpers.tpl Normal file
View File

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

View File

@ -0,0 +1,15 @@
{{- with .Values.certificate.certmanager }}
{{- if and .enabled (not $.Values.certificate.secretName) ($.Capabilities.APIVersions.Has "cert-manager.io/v1/Certificate") }}
---
apiVersion: "cert-manager.io/v1"
kind: Certificate
metadata:
name: {{ include "stalwart-mail.fullname" $ }}
spec:
secretName: {{ include "stalwart-mail.fullname" $ }}-cert
issuerRef:
{{- toYaml .issuerRef | nindent 4 }}
dnsNames:
{{- toYaml .dnsNames | nindent 4 }}
{{- end }}{{/* end-if .enabled */}}
{{- end }}{{/* end-with .certificates */}}

9
templates/configmap.yaml Normal file
View File

@ -0,0 +1,9 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: { { include "stalwart-mail.fullname" . } }
labels: { { - include "stalwart-mail.labels" . | nindent 4 } }
data:
'config.toml': |
{{- toToml .Values.config | replace ".0\n" "\n" | nindent 4 }}

117
templates/deployment.yaml Normal file
View File

@ -0,0 +1,117 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "stalwart-mail.fullname" . }}
labels:
{{- include "stalwart-mail.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "stalwart-mail.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
config-hash: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
secret-env-hash: {{ include (print $.Template.BasePath "/secrets-env.yaml") . | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "stalwart-mail.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "stalwart-mail.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
{{- with .Values.image}}
image: "{{ coalesce $.Values.global.image.registry .registry }}/{{ .repository }}:{{ .tag | default (printf "v%s" $.Chart.AppVersion) }}"
imagePullPolicy: {{ coalesce $.Values.global.image.pullPolicy .pullPolicy }}
{{- end }}
{{- with .Values.env }}
env:
{{- toYaml . | nindent 12 }}
{{- end }}
envFrom:
- secretRef:
name: {{ include "stalwart-mail.fullname" . }}-env
ports:
{{- range $name, $port := .Values.service.ports }}
- name: {{ $name }}
containerPort: {{ $port }}
protocol: TCP
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: "/data"
- name: data
mountPath: "/data/blobs"
subPath: "blobs"
- name: data
mountPath: "/data/queue"
subPath: "queue"
- name: data
mountPath: "/data/reports"
subPath: reports
- name: config
mountPath: "/opt/stalwart-mail/etc/config.toml"
subPath: "config.toml"
readOnly: false
{{- if or .Values.certificate.secretName .Values.certificate.certmanager.enabled }}
- name: certificate
mountPath: "/opt/stalwart-mail/etc/certs"
{{- end }}
{{- with .Values.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: "config"
configMap:
name: {{ include "stalwart-mail.fullname" . }}
{{- if or .Values.certificate.secretName .Values.certificate.certmanager.enabled }}
- name: certificate
secret:
secretName: {{ .Values.certificate.secretName | default (printf "%s-cert" (include "stalwart-mail.fullname" .)) }}
{{- end }}
- name: "data"
{{- if .Values.persistence.enabled }}
{{- if .Values.persistence.hostPath }}
hostPath:
type: Directory
path: {{ .Values.persistence.hostPath | quote }}
{{- else }}{{/* else .persistence.hostPath */}}
persistentVolumeClaim:
claimName: {{ coalesce .Values.persistence.existingClaim (include "stalwart-mail.fullname" .) }}
{{- end }}{{/* end-else .persistence.hostPath */}}
{{- else }}{{/* else .persistence.enabled */}}
emptyDir: {}
{{- end }}{{/* end-else .persistence.enabled */}}
{{- with .Values.volumes }}
{{- 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 }}

32
templates/hpa.yaml Normal file
View File

@ -0,0 +1,32 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "stalwart-mail.fullname" . }}
labels:
{{- include "stalwart-mail.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "stalwart-mail.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

61
templates/ingress.yaml Normal file
View File

@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "stalwart-mail.fullname" . -}}
{{- $svcPort := .Values.service.ports.http -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "stalwart-mail.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

28
templates/pvc.yaml Normal file
View File

@ -0,0 +1,28 @@
{{- with .Values.persistence }}
{{- if and .enabled (not .existingClaim) }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ template "stalwart-mail.fullname" $ }}
labels:
{{- include "stalwart-mail.labels" $ | nindent 4 }}
{{- with .annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
accessModes:
- {{ .accessMode | quote }}
resources:
requests:
storage: {{ .size | quote }}
{{- with .storageClass }}
{{- if (eq "-" .) }}
storageClassName: ""
{{- else }}
storageClassName: {{ . | quote }}
{{- end }}
{{- end }}
{{- end }}{{/* end-if .enabled */}}
{{- end }}{{/* end-with .persistence */}}

View File

@ -0,0 +1,11 @@
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "stalwart-mail.fullname" . }}-env
labels:
{{- include "stalwart-mail.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.secrets.env }}
{{ $key }}: {{ $value | b64enc }}
{{- end }}

26
templates/service.yaml Normal file
View File

@ -0,0 +1,26 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "stalwart-mail.fullname" . }}
labels:
{{- include "stalwart-mail.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.service }}
type: {{ .type }}
ipFamilyPolicy: {{ .ipFamilyPolicy }}
ipFamilies:
{{- toYaml .ipFamilies | nindent 4 }}
ports:
{{- range $name, $port := .ports }}
- port: {{ $port }}
targetPort: {{ $name }}
protocol: TCP
name: {{ $name }}
{{- end }}
{{- end }}{{/* end-with .service */}}
selector:
{{- include "stalwart-mail.selectorLabels" . | nindent 4 }}

View File

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

21
templates/traefik.yaml Normal file
View File

@ -0,0 +1,21 @@
{{- if .Values.traefik.enabled }}
{{- range $port,$entryport := .Values.traefik.ports }}
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: {{ include "stalwart-mail.fullname" $ }}-{{ $port }}
spec:
entryPoints:
- {{ $entryport }}
routes:
- match: HostSNI(`{{ $.Values.traefik.host }}`)
services:
- name: {{ include "stalwart-mail.fullname" $ }}
port: {{ $port }}
proxyProtocol:
version: 2
tls:
passthrough: true
{{- end }}
{{- end }}{{/* end-if .enabled */}}

266
values.yaml Normal file
View File

@ -0,0 +1,266 @@
# Default values for stalwart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
global:
image:
# -- if set it will overwrite all registry entries
registry:
# -- if set it will overwrite all pullPolicy
pullPolicy:
replicaCount: 1
image:
registry: docker.io
repository: stalwartlabs/mail-server
pullPolicy: IfNotPresent
# -- Overrides the image tag whose default is the chart appVersion.
tag: ''
imagePullSecrets: []
nameOverride: ''
fullnameOverride: ''
config:
server:
listener:
smtp:
bind: ['[::]:25']
protocol: 'smtp'
submission:
bind: ['[::]:587']
protocol: 'smtp'
submissions:
bind: ['[::]:465']
protocol: 'smtp'
tls:
implicit: true
imap:
bind: ['[::]:143']
protocol: 'imap'
imaptls:
bind: ['[::]:993']
protocol: 'imap'
tls:
implicit: true
sieve:
bind: ['[::]:4190']
protocol: 'managesieve'
https:
protocol: 'http'
bind: ['[::]:80']
tls:
implicit: true
run-as:
# -- server run-as user
user: 'stalwart-mail'
# -- server run-as group
group: 'stalwart-mail'
storage:
data: 'rocksdb'
fts: 'rocksdb'
blob: 'rocksdb'
lookup: 'rocksdb'
directory: 'internal'
store:
rocksdb:
type: rocksdb
path: '/data'
compression: 'lz4'
directory:
internal:
type: 'internal'
store: 'rocksdb'
tracer:
otel:
enable: false
type: 'open-telemetry'
level: 'info'
# -- grpc or http
transport: 'grpc'
endpoint: 'https://127.0.0.1/otel'
# -- headers for usage with http (e.g. 'Authorization: <place_auth_here>')
headers: []
stdout:
enable: true
type: 'stdout'
level: 'info'
ansi: false
auth:
dkim:
# -- auth rule for signing with dkim
# @section -- DKIM
sign:
- if: "listener != 'smtp'"
then: "['rsa', 'ed25519']"
- else: false
# -- verify of dkim signature (relaxed, strict, disable)
# @section -- DKIM
verify: 'relaxed'
authentication:
fallback-admin:
# -- username for fallback authentfication
# @section -- Authentification
user: 'admin'
# -- password for fallback authentfication (use env for store in secrets of kubernetes)
# @section -- Authentification
secret: '%{env:FALLBACK_ADMIN_SECRET}%'
secrets:
env:
# -- password for fallback authentfication (env)
# @section -- Authentification
FALLBACK_ADMIN_SECRET: supersecret
serviceAccount:
# Specifies whether a service account should be created
create: false
# 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: ''
podAnnotations: {}
podLabels: {}
env: []
podSecurityContext:
{}
# fsGroup: 2000
securityContext:
{}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
ipFamilies: ['IPv4']
# -- other option is RequireDualStack
ipFamilyPolicy: 'SingleStack'
annotations: {}
ports:
smtp: 25
smtp-submission: 587
smtps: 465
imap: 143
imaps: 993
sieve: 4190
http: 80
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
traefik:
enabled: false
ports:
http: websecure
imaps: imaps
smtps: smtps
certificate:
# -- not needed if certmanager is used
secretName:
certmanager:
enabled: true
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-prod
dnsNames:
- 'chart-example.local'
resources:
{}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
# Additional volumes on the output Deployment definition.
volumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
# Additional volumeMounts on the output Deployment definition.
volumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
nodeSelector: {}
tolerations: []
affinity: {}
persistence:
# -- Enable persistence using Persistent Volume Claims
# ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
enabled: true
annotations: {}
# -- Persistent Volume Storage Class
# If defined, storageClassName: <storageClass>
# If set to "-", storageClassName: "", which disables dynamic provisioning
# If undefined (the default) or set to null, no storageClassName spec is
# set, choosing the default provisioner. (gp2 on AWS, standard on
# GKE, AWS & OpenStack)
storageClass:
# -- A manually managed Persistent Volume and Claim
# Requires persistence.enabled: true
# If defined, PVC must be created manually before volume will be bound
existingClaim:
# -- Do not create an PVC, direct use hostPath in Pod
hostPath:
# -- accessMode
accessMode: ReadWriteOnce
# -- size
size: 10Gi