--- # Sentinel-managed Valkey for rspamd (bayes, history, ratelimit, gpt cache). # rspamd has no Redis Cluster support, so the valkey-operator (cluster mode) # cannot be used. start.sh follows the master the sentinels report; on a full # restart the highest replication offset wins. Hostnames carry a trailing dot so # lookups of a deleted pod fail fast instead of walking the search list (sentinel TILT). apiVersion: apps/v1 kind: StatefulSet metadata: name: rspamd-valkey namespace: mail annotations: configmap.reloader.stakater.com/reload: "rspamd-valkey-scripts" spec: serviceName: rspamd-valkey podManagementPolicy: Parallel replicas: 3 selector: matchLabels: app.kubernetes.io/name: rspamd-valkey template: metadata: labels: app.kubernetes.io/name: rspamd-valkey spec: automountServiceAccountToken: false topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app.kubernetes.io/name: rspamd-valkey securityContext: runAsNonRoot: true runAsUser: 999 runAsGroup: 999 fsGroup: 999 seccompProfile: type: RuntimeDefault containers: - name: valkey image: docker.io/valkey/valkey:9.0.0 imagePullPolicy: IfNotPresent command: ["sh", "/scripts/start.sh", "valkey"] env: - name: DOMAIN_SUFFIX value: .rspamd-valkey.mail.svc.cluster.local. ports: - containerPort: 6379 name: valkey protocol: TCP readinessProbe: exec: command: ["sh", "-c", "valkey-cli info replication | grep -q '^master_host:127.0.0.1' && exit 1; valkey-cli ping | grep -q PONG"] initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: exec: command: ["valkey-cli", "ping"] initialDelaySeconds: 30 periodSeconds: 30 securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL resources: requests: cpu: 50m memory: 128Mi limits: cpu: 500m memory: 512Mi volumeMounts: - name: data mountPath: /data - name: scripts mountPath: /scripts readOnly: true - name: sentinel image: docker.io/valkey/valkey:9.0.0 imagePullPolicy: IfNotPresent command: ["sh", "/scripts/start.sh", "sentinel"] env: - name: DOMAIN_SUFFIX value: .rspamd-valkey.mail.svc.cluster.local. ports: - containerPort: 26379 name: sentinel protocol: TCP readinessProbe: exec: command: ["valkey-cli", "-p", "26379", "ping"] initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: exec: command: ["valkey-cli", "-p", "26379", "ping"] initialDelaySeconds: 30 periodSeconds: 30 securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL resources: requests: cpu: 10m memory: 32Mi limits: cpu: 100m memory: 64Mi volumeMounts: - name: sentinel mountPath: /sentinel - name: scripts mountPath: /scripts readOnly: true volumes: - name: scripts configMap: name: rspamd-valkey-scripts - name: sentinel emptyDir: {} volumeClaimTemplates: - metadata: name: data spec: accessModes: [ReadWriteOnce] storageClassName: cephrbd-fast-delete resources: requests: storage: 5Gi --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: rspamd-valkey namespace: mail spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: rspamd-valkey --- # Stable per-pod DNS, published before readiness so replicas can find the seed. apiVersion: v1 kind: Service metadata: name: rspamd-valkey namespace: mail spec: clusterIP: None publishNotReadyAddresses: true selector: app.kubernetes.io/name: rspamd-valkey ports: - name: valkey port: 6379 targetPort: valkey - name: sentinel port: 26379 targetPort: sentinel --- apiVersion: v1 kind: Service metadata: name: rspamd-valkey-sentinel namespace: mail spec: type: ClusterIP selector: app.kubernetes.io/name: rspamd-valkey ports: - name: sentinel port: 26379 targetPort: sentinel