--- apiVersion: apps/v1 kind: StatefulSet metadata: name: stalwart namespace: mail annotations: secret.reloader.stakater.com/reload: "stalwart-admin,stalwart-db-app,stalwart-blobs-s3,wildcard-unkin-net-tls,vault-ca-cert,stalwart-db-ca" spec: # Nodes coordinate through mail-valkey; each leases its cluster node id by # hostname, so stable pod names keep a stable id across restarts. replicas: 3 serviceName: stalwart-headless podManagementPolicy: Parallel updateStrategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: stalwart template: metadata: labels: app.kubernetes.io/name: stalwart mail.unkin.net/smarthost-client: "true" spec: securityContext: runAsNonRoot: true runAsUser: 2000 runAsGroup: 2000 fsGroup: 2000 seccompProfile: type: RuntimeDefault topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: stalwart # rustls loads SSL_CERT_FILE, so public roots, the internal CA (RGW) and the CNPG CA go in one bundle. initContainers: - name: combine-certs image: docker.io/stalwartlabs/stalwart:v0.16.25 command: - sh - -c - cat /etc/ssl/certs/ca-certificates.crt /custom-ca/ca.crt /db-ca/ca.crt > /combined-certs/ca-certificates.crt securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL resources: limits: cpu: 100m memory: 64Mi requests: cpu: 25m memory: 32Mi volumeMounts: - name: vault-ca-cert mountPath: /custom-ca readOnly: true - name: db-ca mountPath: /db-ca readOnly: true - name: combined-certs mountPath: /combined-certs containers: - name: stalwart image: docker.io/stalwartlabs/stalwart:v0.16.25 imagePullPolicy: IfNotPresent env: - name: STALWART_HOSTNAME valueFrom: fieldRef: fieldPath: metadata.name - name: SSL_CERT_FILE value: /etc/ssl/combined/ca-certificates.crt - name: DB_PASSWORD valueFrom: secretKeyRef: name: stalwart-db-app key: password - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: name: stalwart-blobs-s3 key: AWS_ACCESS_KEY_ID - name: AWS_SECRET_ACCESS_KEY valueFrom: secretKeyRef: name: stalwart-blobs-s3 key: AWS_SECRET_ACCESS_KEY - name: ADMIN_USERNAME valueFrom: secretKeyRef: name: stalwart-admin key: username - name: ADMIN_PASSWORD valueFrom: secretKeyRef: name: stalwart-admin key: password - name: STALWART_RECOVERY_ADMIN value: "$(ADMIN_USERNAME):$(ADMIN_PASSWORD)" ports: - containerPort: 8080 name: http protocol: TCP - containerPort: 443 name: https protocol: TCP - containerPort: 24 name: lmtp protocol: TCP - containerPort: 465 name: submissions protocol: TCP - containerPort: 587 name: submission protocol: TCP - containerPort: 993 name: imaps protocol: TCP - containerPort: 9090 name: metrics protocol: TCP livenessProbe: httpGet: path: /healthz/live port: http initialDelaySeconds: 30 periodSeconds: 30 timeoutSeconds: 5 readinessProbe: httpGet: path: /healthz/ready port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL # the binary carries a cap_net_bind_service file capability; exec fails without it add: - NET_BIND_SERVICE resources: limits: cpu: "2" memory: 2Gi requests: cpu: 100m memory: 512Mi volumeMounts: - name: config mountPath: /etc/stalwart/config.json subPath: config.json readOnly: true - name: tls mountPath: /etc/stalwart/tls readOnly: true - name: combined-certs mountPath: /etc/ssl/combined readOnly: true - name: data mountPath: /var/lib/stalwart - name: tmp mountPath: /tmp volumes: - name: config configMap: name: stalwart-config - name: tls secret: secretName: wildcard-unkin-net-tls - name: vault-ca-cert secret: secretName: vault-ca-cert items: - key: ca.crt path: ca.crt - name: db-ca secret: secretName: stalwart-db-ca items: - key: ca.crt path: ca.crt - name: combined-certs emptyDir: {} # Webui unpack dir only; mail data is in Postgres and S3. - name: data emptyDir: {} - name: tmp emptyDir: {}