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 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 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#