Setup Redis¶
How to deploy Redis for Mailu session storage and caching.
Problem¶
Mailu requires Redis for session storage and caching. You need to deploy Redis before deploying Mailu.
Solution¶
Deploy Redis using the Bitnami Helm chart. For most Mailu deployments, a simple single-instance Redis is sufficient since sessions can be regenerated if Redis fails.
Prerequisites¶
Helm 3 installed
Kubernetes cluster
Persistent storage (optional for session data)
Step 1: Add Bitnami Helm Repository¶
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
Step 2: Choose Deployment Mode¶
Option A: Standalone (Recommended for Most Cases)¶
Simple single-instance Redis. Suitable for:
Development and testing
Small to medium deployments (< 500 users)
Environments where brief session loss is acceptable
Option B: Master-Replica (High Availability)¶
Master with read replicas. Use when:
High availability is critical
Large deployments (500+ users)
Zero downtime required
Option C: Sentinel (Automatic Failover)¶
Redis with Sentinel for automatic failover. Use when:
Production critical workload
Automatic failover required
Multiple replicas with coordinator
Deploy Standalone Redis (Recommended)¶
Create Values File¶
Create redis-values.yaml:
# Bitnami Redis configuration for Mailu
architecture: standalone
auth:
enabled: false # Mailu supports Redis without authentication (cluster-internal)
# Or enable authentication:
# enabled: true
# password: "CHANGE_ME_SECURE_PASSWORD"
master:
persistence:
enabled: true # Persist data (optional for sessions)
size: 5Gi
storageClass: longhorn
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
# Disable persistence if sessions-only (faster, but data lost on restart)
# persistence:
# enabled: false
metrics:
enabled: true
resources:
requests:
cpu: 50m
memory: 64Mi
Install Redis¶
# Create namespace
kubectl create namespace redis
# Install Redis
helm install redis bitnami/redis \
--namespace redis \
--values redis-values.yaml
# Wait for pod to be ready
kubectl wait --for=condition=ready pod -n redis -l app.kubernetes.io/name=redis --timeout=300s
Verify Installation¶
# Check pod status
kubectl get pods -n redis
# Test Redis connection
kubectl exec -n redis redis-master-0 -- redis-cli ping
# Should return: PONG
# Check Redis info
kubectl exec -n redis redis-master-0 -- redis-cli info server
Get Connection Details¶
# Get service name
kubectl get svc -n redis
# Service name will be: redis-master
# Connection string: redis-master.redis.svc.cluster.local:6379
Configure Mailu (No Authentication)¶
If Redis has auth.enabled: false:
redis: {
host: 'redis-master.redis.svc.cluster.local',
port: 6379,
// No secretName needed
}
Configure Mailu (With Authentication)¶
If Redis has auth.enabled: true, create secret:
# Get Redis password from Helm release
REDIS_PASSWORD=$(kubectl get secret -n redis redis -o jsonpath='{.data.redis-password}' | base64 -d)
# Create secret for Mailu
kubectl create secret generic redis-password \
--namespace=mailu \
--from-literal=password="$REDIS_PASSWORD"
Configure in CDK8S:
redis: {
host: 'redis-master.redis.svc.cluster.local',
port: 6379,
secretName: 'redis-password',
secretKey: 'password',
}
Deploy Master-Replica Redis (High Availability)¶
Create Values File¶
Create redis-ha-values.yaml:
# Redis Master-Replica configuration
architecture: replication
auth:
enabled: false # Or true for authentication
replica:
replicaCount: 2 # Number of read replicas
master:
persistence:
enabled: true
size: 5Gi
storageClass: longhorn
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
replica:
persistence:
enabled: true
size: 5Gi
storageClass: longhorn
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
metrics:
enabled: true
Install Redis HA¶
helm install redis bitnami/redis \
--namespace redis \
--values redis-ha-values.yaml
# Wait for all pods
kubectl wait --for=condition=ready pod -n redis -l app.kubernetes.io/name=redis --timeout=300s
Verify Replication¶
# Check master
kubectl exec -n redis redis-master-0 -- redis-cli info replication
# Should show:
# role:master
# connected_slaves:2
# Check replica
kubectl exec -n redis redis-replicas-0 -- redis-cli info replication
# Should show:
# role:slave
# master_host:redis-master-0
Configure Mailu with HA Redis¶
Use the master service for writes:
redis: {
host: 'redis-master.redis.svc.cluster.local', // Write to master
port: 6379,
}
Note: Mailu connects to master for both reads and writes. Read replicas are used automatically by the Redis client for load balancing.
Deploy Redis Sentinel (Automatic Failover)¶
Create Values File¶
Create redis-sentinel-values.yaml:
# Redis Sentinel configuration
sentinel:
enabled: true
replicas: 3 # Sentinel instances (odd number recommended)
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
master:
persistence:
enabled: true
size: 5Gi
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
replica:
replicaCount: 2
persistence:
enabled: true
size: 5Gi
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
auth:
enabled: false # Or true
sentinel: false # Sentinel auth (usually false for internal cluster)
metrics:
enabled: true
Install Redis Sentinel¶
helm install redis bitnami/redis \
--namespace redis \
--values redis-sentinel-values.yaml
kubectl wait --for=condition=ready pod -n redis -l app.kubernetes.io/name=redis --timeout=600s
Verify Sentinel¶
# Check Sentinel status
kubectl exec -n redis redis-node-0 -- \
redis-cli -p 26379 sentinel master mymaster
# Should show master details and number of slaves and sentinels
Configure Mailu with Sentinel¶
redis: {
host: 'redis.redis.svc.cluster.local', // Sentinel service
port: 6379, // Redis port (Sentinel handles failover)
// Sentinel configuration in Mailu is automatic with standard Bitnami setup
}
Persistence Considerations¶
With Persistence (Default)¶
Pros:
Session data survives pod restarts
Cached data persists
Better for production
Cons:
Requires PVC storage
Slower restarts (load data from disk)
Without Persistence¶
Pros:
Faster pod restarts
No storage overhead
Simpler setup
Cons:
All sessions lost on restart (users must re-login)
Cache data regenerated on restart
When to disable persistence: Development/testing where session loss is acceptable.
master:
persistence:
enabled: false
Monitoring Redis¶
Check Memory Usage¶
kubectl exec -n redis redis-master-0 -- \
redis-cli info memory | grep used_memory_human
Check Connected Clients¶
kubectl exec -n redis redis-master-0 -- \
redis-cli info clients | grep connected_clients
Check Hit Rate¶
kubectl exec -n redis redis-master-0 -- \
redis-cli info stats | grep keyspace
Monitor Keys¶
# Count keys
kubectl exec -n redis redis-master-0 -- \
redis-cli dbsize
# List all keys (be careful in production!)
kubectl exec -n redis redis-master-0 -- \
redis-cli --scan
# List Mailu session keys
kubectl exec -n redis redis-master-0 -- \
redis-cli --scan --pattern "session:*"
Scaling Redis¶
Increase Memory¶
Edit redis-values.yaml:
master:
resources:
requests:
memory: 512Mi # Increased
limits:
memory: 1Gi # Increased
Apply changes:
helm upgrade redis bitnami/redis \
--namespace redis \
--values redis-values.yaml
# Pod will restart with new resources
kubectl rollout status statefulset -n redis redis-master
Add More Replicas (HA Mode)¶
Edit redis-ha-values.yaml:
replica:
replicaCount: 3 # Increased from 2
Apply:
helm upgrade redis bitnami/redis \
--namespace redis \
--values redis-ha-values.yaml
Troubleshooting¶
Pod not starting¶
# Check pod status
kubectl describe pod -n redis redis-master-0
# Check logs
kubectl logs -n redis redis-master-0
# Common causes:
# - PVC not bound (check storage class)
# - Resource limits too low
# - Port already in use
Cannot connect to Redis¶
# Test from another pod
kubectl run -it --rm redis-test --image=redis:7 --restart=Never -- \
redis-cli -h redis-master.redis.svc.cluster.local ping
# Should return: PONG
# Check service
kubectl get svc -n redis
Authentication errors¶
# Get Redis password
kubectl get secret -n redis redis -o jsonpath='{.data.redis-password}' | base64 -d
# Test with password
kubectl exec -n redis redis-master-0 -- \
redis-cli -a "<password>" ping
High memory usage¶
# Check memory stats
kubectl exec -n redis redis-master-0 -- \
redis-cli info memory
# Check key distribution
kubectl exec -n redis redis-master-0 -- \
redis-cli --bigkeys
# Flush keys if needed (CAREFUL - deletes all data!)
# kubectl exec -n redis redis-master-0 -- redis-cli FLUSHALL
Replication lag (HA mode)¶
# Check replica status
kubectl exec -n redis redis-replicas-0 -- \
redis-cli info replication | grep master_link_status
# Should show: master_link_status:up
# Check lag
kubectl exec -n redis redis-replicas-0 -- \
redis-cli info replication | grep master_repl_offset
Performance Tuning¶
Optimize for Session Storage¶
Mailu primarily uses Redis for short-lived session data:
master:
configuration: |-
# Optimize for session storage
maxmemory 256mb
maxmemory-policy allkeys-lru # Evict least recently used keys
save "" # Disable snapshotting if persistence disabled
Connection Pooling¶
Redis handles connections efficiently. Typical settings:
master:
configuration: |-
maxclients 1000
timeout 300
Redis vs Alternatives¶
Why Redis for Mailu?¶
✅ Fast in-memory storage
✅ Built-in expiration (TTL) for sessions
✅ Simple key-value model
✅ Low resource overhead
✅ Widely supported
Could You Use Memcached?¶
No, Mailu requires Redis specifically. Mailu uses Redis-specific features like:
Key expiration (TTL)
Hash data structures
Pub/sub (for certain operations)
Cleanup and Removal¶
Uninstall Redis¶
# Uninstall Helm release
helm uninstall redis --namespace redis
# Delete PVCs (data will be lost!)
kubectl delete pvc -n redis -l app.kubernetes.io/name=redis
# Delete namespace
kubectl delete namespace redis
Warning: This deletes all session data. Users will need to re-login to Mailu.
See Also¶
Setup PostgreSQL - Deploy database for Mailu
Manage Secrets - Creating Redis password secrets
Quick Start - Deploy Mailu with Redis
Component Specifications - Redis requirements
Bitnami Redis Chart - Official Helm chart docs