diff --git a/apps/stalwart/stalwart-fresh-deployment.yaml b/apps/stalwart/stalwart-fresh-deployment.yaml index e4a5f69..7f817e4 100644 --- a/apps/stalwart/stalwart-fresh-deployment.yaml +++ b/apps/stalwart/stalwart-fresh-deployment.yaml @@ -144,6 +144,14 @@ spec: limits: memory: "2Gi" cpu: "2000m" + startupProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 livenessProbe: httpGet: path: / @@ -225,6 +233,10 @@ spec: set -e echo "Starting Stalwart backup at $(date)" + # Build restic repository URL from env vars (K8s doesn't expand $(VAR) in value fields) + export RESTIC_REPOSITORY="s3:${S3_ENDPOINT}/${S3_BUCKET}/stalwart" + echo "Using repository: $RESTIC_REPOSITORY" + # Initialize restic repo if needed restic snapshots || restic init @@ -243,8 +255,6 @@ spec: echo "Backup completed successfully at $(date)" env: - - name: RESTIC_REPOSITORY - value: "s3:$(S3_ENDPOINT)/$(S3_BUCKET)/stalwart" - name: RESTIC_PASSWORD valueFrom: secretKeyRef: diff --git a/apps/stalwart/stalwart-monitoring.yaml b/apps/stalwart/stalwart-monitoring.yaml new file mode 100644 index 0000000..0c20a97 --- /dev/null +++ b/apps/stalwart/stalwart-monitoring.yaml @@ -0,0 +1,132 @@ +--- +# ServiceMonitor for Stalwart application metrics +# Requires prometheus-operator to be installed +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: stalwart-metrics + namespace: stalwart + labels: + app: stalwart + release: kube-prometheus-stack +spec: + selector: + matchLabels: + app: stalwart + endpoints: + - port: http + interval: 30s + path: /metrics + scheme: http +--- +# Blackbox exporter probe for external health check +# Tests the full service path from outside the cluster +apiVersion: v1 +kind: Service +metadata: + name: stalwart-external-probe + namespace: stalwart + labels: + app: stalwart-probe +spec: + type: ClusterIP + clusterIP: None # Headless service for probe + selector: + app: stalwart-probe-dummy # No pods, just for ServiceMonitor +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: stalwart-blackbox-external + namespace: stalwart + labels: + app: stalwart + release: kube-prometheus-stack +spec: + selector: + matchLabels: + app: stalwart-probe + endpoints: + - port: http + interval: 60s + scrapeTimeout: 30s + path: /probe + params: + module: [http_2xx] + target: ['https://mail.basicstack.de/'] + relabelings: + - sourceLabels: [__address__] + targetLabel: __param_target + - sourceLabels: [__param_target] + targetLabel: instance + - targetLabel: __address__ + replacement: prometheus-blackbox-exporter.observability.svc.cluster.local:9115 +--- +# PrometheusRule for alerting on Stalwart failures +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: stalwart-alerts + namespace: stalwart + labels: + app: stalwart + release: kube-prometheus-stack +spec: + groups: + - name: stalwart.rules + interval: 30s + rules: + - alert: StalwartDown + expr: up{job="stalwart-metrics"} == 0 + for: 2m + labels: + severity: critical + service: stalwart + component: mail + annotations: + summary: "Stalwart mail service is down" + description: "Stalwart pod in namespace {{ $labels.namespace }} has been unreachable for more than 2 minutes." + + - alert: StalwartExternalProbeFailure + expr: probe_success{job="stalwart-blackbox-external"} == 0 + for: 5m + labels: + severity: critical + service: stalwart + component: external-access + annotations: + summary: "Stalwart external endpoint unreachable" + description: "External probe to {{ $labels.instance }} has failed for more than 5 minutes. Users cannot access mail service." + + - alert: StalwartHighResponseTime + expr: probe_http_duration_seconds{job="stalwart-blackbox-external"} > 5 + for: 5m + labels: + severity: warning + service: stalwart + component: performance + annotations: + summary: "Stalwart responding slowly" + description: "Stalwart response time to {{ $labels.instance }} is {{ $value }}s (threshold: 5s)." + + - alert: StalwartPodRestarting + expr: rate(kube_pod_container_status_restarts_total{namespace="stalwart",pod=~"stalwart-.*"}[15m]) > 0 + for: 5m + labels: + severity: warning + service: stalwart + component: stability + annotations: + summary: "Stalwart pod restarting" + description: "Stalwart pod {{ $labels.pod }} has restarted {{ $value }} times in the last 15 minutes." + + - alert: StalwartBackupFailing + expr: kube_job_status_failed{namespace="stalwart",job_name=~"stalwart-backup-.*"} > 0 + for: 1h + labels: + severity: warning + service: stalwart + component: backup + annotations: + summary: "Stalwart backup job failing" + description: "Backup job {{ $labels.job_name }} has failed. Investigate backup configuration."