Building a self-hosted Redis server on a Kubernetes cluster, especially on Red Hat servers, involves several key steps. We’ll cover deploying a single-instance Redis with persistence, and then discuss high-availability options and Red Hat/OpenShift specific considerations.
This guide assumes you already have a Kubernetes cluster up and running on your Red Hat servers (e.g., using kubeadm, OpenShift Container Platform, or other methods).
Part 1: Prerequisites
- Kubernetes Cluster: A functional Kubernetes cluster (v1.18+ recommended).
kubectl: Configured to connect to your cluster.StorageClass: A defaultStorageClassconfigured in your cluster for dynamic PersistentVolume provisioning. If not, you’ll need to manually createPersistentVolumeobjects. Common storage solutions for Red Hat environments include:- Ceph/Rook: A robust, open-source distributed storage system often integrated with OpenShift.
- NFS: Network File System, simple to set up but less robust for production K8s.
- Local Persistent Volumes: Using disk space directly on the node, but requires careful management for HA.
- Cloud Provider Storage: If your RHEL VMs are on a cloud (AWS EBS, Azure Disk, GCP Persistent Disk).
- Red Hat Specifics (for OpenShift): If you’re using OpenShift, you’ll need to be aware of Security Context Constraints (SCCs). The default
restrictedSCC often prevents pods from running asrootor using certain host paths, which can impact deployments if not configured correctly. We’ll address this.
Part 2: Deploying a Single-Instance Redis with Persistence
For a single, stateful application like Redis, a StatefulSet is generally preferred over a Deployment because it provides stable network identifiers, ordered graceful scaling, and persistent storage via volumeClaimTemplates.
We’ll use:
Namespace: To isolate our Redis resources.ConfigMap: To store the Redis configuration file (redis.conf).Secret: To store sensitive information like the Redis password.StatefulSet: To manage the Redis pod(s) and their persistent storage.Service: To provide a stable network endpoint for other applications to connect to Redis.
Step 1: Create a Namespace
It’s good practice to isolate your applications in their own namespaces.
# redis-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: redis-production
Apply it:
kubectl apply -f redis-namespace.yaml
Step 2: Create a ConfigMap for Redis Configuration
This allows you to customize redis.conf. For a basic setup, appendonly yes is crucial for data persistence.
# redis-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: redis-production
data:
redis.conf: |
# Basic Redis configuration
port 6379
bind 0.0.0.0
# Enable AOF persistence for data durability
appendonly yes
appendfsync everysec
# Set a maximum memory usage (adjust as needed)
# This prevents Redis from consuming all available memory.
# When maxmemory is reached, Redis will start evicting keys based on the policy.
maxmemory 2gb # Example: 2GB. Adjust based on your data and server capacity.
maxmemory-policy allkeys-lru # Least Recently Used eviction policy
# RDB persistence (snapshotting)
save 900 1
save 300 10
save 60 10000
# Set log level to verbose
loglevel verbose
# Disable protected mode (only if bind 0.0.0.0 is used and firewalls are in place)
# For production, ensure network policies are strict.
protected-mode no
Apply it:
kubectl apply -f redis-configmap.yaml
Step 3: Create a Secret for the Redis Password
Important: Never hardcode passwords in your YAML files directly. Use Kubernetes Secrets.
# redis-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: redis-password
namespace: redis-production
type: Opaque
stringData:
password: your_secure_redis_password_here # <<-- CHANGE THIS TO A STRONG PASSWORD
Apply it:
kubectl apply -f redis-secret.yaml
Step 4: Create the Redis StatefulSet
This defines the Redis pod, its persistent storage, and how it uses the ConfigMap and Secret.
# redis-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: redis-production
spec:
serviceName: "redis-service" # This must match the Service's name below
replicas: 1 # Start with 1 replica for a single instance
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:6.2.7-alpine # Use a specific, stable version. Consider Red Hat UBI images for OpenShift.
imagePullPolicy: IfNotPresent
command: ["redis-server"]
args:
- "/etc/redis/redis.conf" # Mount our config file
- "--requirepass"
- "$(REDIS_PASSWORD)" # Use the password from the Secret
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: redis-password
key: password
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: redis-config # Mount the ConfigMap as a volume
mountPath: /etc/redis
- name: redis-data # Mount the persistent volume for data
mountPath: /data
livenessProbe:
exec:
command:
- redis-cli
- -a
- "$(REDIS_PASSWORD)"
- ping
initialDelaySeconds: 15
timeoutSeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
readinessProbe:
exec:
command:
- redis-cli
- -a
- "$(REDIS_PASSWORD)"
- ping
initialDelaySeconds: 5
timeoutSeconds: 3
periodSeconds: 5
successThreshold: 1
failureThreshold: 3
volumes:
- name: redis-config
configMap:
name: redis-config
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: standard # <<-- CHANGE THIS to your cluster's default or desired StorageClass
resources:
requests:
storage: 5Gi # <<-- CHANGE THIS to your desired storage size
Important Notes for redis-statefulset.yaml:
image: For production, use a specific, stable tag (e.g.,redis:6.2.7-alpine). On OpenShift, you might prefer a Red Hat Universal Base Image (UBI) based image if available for Redis, or ensure the base image is compatible with OpenShift’s SCCs.storageClassName: This must match aStorageClassdefined in your Kubernetes cluster. Replacestandardwith the name of your desiredStorageClass. If you don’t have one, you’ll need to provisionPersistentVolumeobjects manually and removestorageClassNamefromvolumeClaimTemplates.resources.requests.storage: Adjust the storage size (5Gi) according to your expected data volume.livenessProbe/readinessProbe: These are crucial for Kubernetes to manage your Redis instance effectively. They check if Redis is running and ready to accept connections. Make sure they use the password from the environment variable.
Apply it:
kubectl apply -f redis-statefulset.yaml
Step 5: Create a Service for Redis
This Service provides a stable internal DNS name (redis-service.redis-production.svc.cluster.local) and IP address for other applications within the cluster to connect to Redis.
# redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: redis-production
spec:
selector:
app: redis # Matches the label on our StatefulSet's pods
ports:
- protocol: TCP
port: 6379
targetPort: 6379
clusterIP: None # headless service for statefulset. If you need a stable ClusterIP for a single instance, remove this line.
Note on clusterIP: None: For a StatefulSet with a single replica, clusterIP: None (a headless service) allows direct access to the pod via its hostname (redis-0.redis-service.redis-production.svc.cluster.local). If you prefer a single stable IP for a single Redis instance, remove the clusterIP: None line, and Kubernetes will assign a ClusterIP. For HA setups, headless services are often preferred for direct pod access.
Apply it:
kubectl apply -f redis-service.yaml
Step 6: Verify the Deployment
Check the status of your resources:
kubectl get all -n redis-production
kubectl get pvc -n redis-production
kubectl describe pod redis-0 -n redis-production
kubectl logs redis-0 -n redis-production
You should see a pod named redis-0 running, a PersistentVolumeClaim named redis-data-redis-0 bound, and the Redis logs indicating it started successfully.
Step 7: Access Redis
From within the cluster (e.g., another pod):
Your application can connect to Redis using the service name: redis-service.redis-production.svc.cluster.local:6379 (or redis-0.redis-service.redis-production.svc.cluster.local:6379 if using the headless service and accessing the specific pod). Remember to use the password defined in your secret.
Example redis-cli access from a temporary pod:
# Get the password
REDIS_PASSWORD=$(kubectl get secret redis-password -n redis-production -o jsonpath='{.data.password}' | base64 --decode)
# Create a temporary busybox pod to test connection
kubectl run -it --rm busybox --image=busybox --namespace redis-production -- /bin/sh
/ # wget -qO- https://download.redis.io/redis-stable/src/redis-cli.c | gcc -xc - -o /usr/bin/redis-cli # compile redis-cli (might need more libs)
# A simpler way is to use a redis-cli image or connect to the Redis pod directly
# Exit busybox, then connect using kubectl exec:
exit
# Connect to redis-cli in the running Redis pod
kubectl exec -it redis-0 -n redis-production -- redis-cli -a "$REDIS_PASSWORD"
# Inside redis-cli:
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set mykey "hello redis"
OK
127.0.0.1:6379> get mykey
"hello redis"
127.0.0.1:6379> quit
From outside the cluster (for testing/debugging, not recommended for production):
kubectl port-forward svc/redis-service 6379:6379 -n redis-production
Then, from your local machine, use redis-cli:
redis-cli -h 127.0.0.1 -p 6379 -a "your_secure_redis_password_here"
Warning: Exposing Redis directly outside the cluster should generally be avoided for production environments due to security risks. If absolutely necessary, consider a NodePort or LoadBalancer service type with strict network policies and firewall rules.
Part 3: High Availability (HA) Options
For production, a single Redis instance is a single point of failure. Kubernetes helps with process restarts, but not data replication or automatic failover. Here are common HA strategies for Redis:
-
Redis Sentinel:
- A system that monitors Redis master and replica instances.
- Automatically promotes a replica to master if the current master fails.
- Requires at least 3 Redis instances (1 master, 2 replicas) and 3 Sentinel instances (on different nodes).
- More complex to set up manually with YAML, often deployed using Helm charts.
-
Redis Cluster:
- Provides sharding (data is partitioned across multiple master nodes) and replication.
- No need for Sentinels as failover is handled by the cluster itself.
- Requires a minimum of 3 master nodes (and typically 1 replica per master for HA, so 6 nodes total).
- Even more complex to set up manually; Helm charts are almost essential here.
Recommendation for HA: Use a Helm Chart
For Redis HA (Sentinel or Cluster), manually writing and maintaining all the Kubernetes YAML can be extremely challenging and error-prone. It’s highly recommended to use a well-maintained Helm chart.
The official Bitnami Redis chart is a popular and robust choice:
- Bitnami Redis Helm Chart (for single node or Sentinel-based HA)
- Bitnami Redis Cluster Helm Chart (for Redis Cluster)
Example Helm Installation (for Sentinel HA):
# Add the Bitnami Helm repository
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
# Install Redis with Sentinel (adjust values as needed)
helm install my-redis-ha bitnami/redis -n redis-production \
--set architecture="replication" \
--set master.persistence.enabled=true \
--set master.persistence.storageClass="standard" \
--set master.persistence.size="10Gi" \
--set replica.replicaCount=2 \
--set replica.persistence.enabled=true \
--set replica.persistence.storageClass="standard" \
--set replica.persistence.size="10Gi" \
--set sentinel.enabled=true \
--set sentinel.replicaCount=3 \
--set auth.password="your_secure_redis_password_here" \
--set metrics.enabled=true # Enable Prometheus metrics if you have monitoring
This example creates a master, two replicas, and three Sentinels, providing robust HA.
Part 4: Red Hat / OpenShift Specific Considerations
If your “Red Hat server” implies using OpenShift Container Platform, there are a few additional points:
-
Security Context Constraints (SCCs):
- OpenShift’s default
restrictedSCC is stricter than vanilla Kubernetes. Pods often run with an arbitrarily assigned user ID, and cannot run asroot(UID 0). - The Redis image typically runs as
root(UID 0) by default to manage file permissions in/data. This might cause permission issues withvolumeMountson OpenShift. - Solution 1 (Recommended): Use a Redis image that explicitly supports running as a non-root user and specify a
securityContextin yourStatefulSet’sspec.template.spec:
You’ll need to ensure the Redis image’s entrypoint can handle this, and that# ... inside spec.template.spec securityContext: fsGroup: 1000 # Example: Assign group 1000 to the volume. runAsUser: 1000 # Example: Run the container as user 1000. containers: - name: redis image: redis:6.2.7-alpine # Some images support non-root, some don't. Test thoroughly. # ... other container settings securityContext: allowPrivilegeEscalation: false # Good practice capabilities: drop: ["ALL"]/datadirectory has appropriate permissions for user 1000. - Solution 2 (Less Ideal, but common): If a non-root image isn’t readily available or causes issues, you might need to relax the SCC for your Redis namespace/service account.
Warning: Granting# Grant the 'anyuid' SCC to the default service account in your namespace oc adm policy add-scc-to-user anyuid -z default -n redis-productionanyuidis less secure as it allows pods to run as any user ID, including root. Only do this if strictly necessary and understand the implications.
- OpenShift’s default
-
Image Streams and Red Hat UBI:
- OpenShift has
ImageStreamsfor managing container images. You can import external images or build your own based on Red Hat’s Universal Base Image (UBI) for better compatibility and support. - Using a
redisimage from a trusted source, possibly built on UBI, is a good practice on OpenShift.
- OpenShift has
-
ocvskubectl:- OpenShift uses the
occommand-line tool, which is a superset ofkubectl. Mostkubectlcommands work, butocprovides additional OpenShift-specific features.
- OpenShift uses the
-
Storage Providers:
- OpenShift Container Storage (OCS) / Rook-Ceph: This is the native, highly recommended persistent storage solution for OpenShift. If you have OCS deployed, you’d use its
StorageClass(e.g.,ocs-storagecluster-cephfsorocs-storagecluster-ceph-rbd).
- OpenShift Container Storage (OCS) / Rook-Ceph: This is the native, highly recommended persistent storage solution for OpenShift. If you have OCS deployed, you’d use its
Part 5: Monitoring and Backups
- Monitoring: Integrate with Prometheus and Grafana. The Redis Helm chart (Bitnami) can enable Prometheus metrics scraping.
- Backups: For production, regularly back up your Redis data.
- Utilize Redis’s built-in RDB snapshots (
SAVEcommand, configured inredis.conf). - Periodically copy the
/datadirectory (containingdump.rdbandappendonly.aof) from your PersistentVolume to an external object storage (S3, Azure Blob, etc.). This might involve a sidecar container or a separate cron job pod that mounts the PVC. - Consider a tool like
Velerofor Kubernetes native backups, which can back up PVs.
- Utilize Redis’s built-in RDB snapshots (
By following these steps, you can successfully deploy a self-hosted, persistent Redis server on your Kubernetes cluster running on Red Hat servers, with considerations for security and future scalability. Remember to adjust resource requests, storage sizes, and passwords to fit your specific environment and needs.

