Triển khai cụm Redis chủ-tủ trong Kubernetes với StatefulSet và PVC

Để xây dựng một cụm Redis có khả năng chịu lỗi cao (high-availability) trên nền tảng Kubernetes, việc sử dụng StatefulSet là lựa chọn tối ưu thay vì Deployment, bởi vì Redis chủ-tủ phụ thuộc vào định danh mạng ổn định, thứ tự khởi động rõ ràng và trạng thái lưu trữ bền vững.

1. Kiến trúc cụm Redis chủ-tủ

Cụm gồm 6 Pod được quản lý bởi một StatefulSet: 1 node chủ (master), 5 node phụ (replica). Mỗi Pod có tên cố định (redis-app-0, redis-app-1, ...), địa chỉ DNS ổn định thông qua Headless Service, và volume riêng biệt để đảm bảo dữ liệu không bị mất khi Pod tái tạo.

2. Lý do chọn StatefulSet

  • Tính ổn định về mạng: Mỗi Pod nhận được một hostname duy nhất và không thay đổi — ví dụ: redis-app-0.redis-service.default.svc.cluster.local.
  • Thứ tự kiểm soát: Pod được tạo và xóa theo thứ tự tuần tự (0 → 1 → 2...), đảm bảo master luôn khởi động trước các replica.
  • Liên kết lưu trữ bền vững: Mỗi Pod gắn với một PersistentVolumeClaim riêng, giữ nguyên dữ liệu giữa các vòng đời.

3. Cấu hình Redis cho môi trường cụm

Tạo file cấu hình redis-cluster.conf:

port 6379
bind 0.0.0.0
protected-mode no
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
supervised kubernetes
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
requirepass mysecretpass
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
cluster-require-full-coverage no
cluster-replica-validity-factor 10
cluster-migration-barrier 1
cluster-allow-reads-when-down yes

Tạo ConfigMap từ file trên:

kubectl create configmap redis-cluster-config --from-file=redis-cluster.conf

4. Triển khai Headless Service

File headless-svc.yaml:

apiVersion: v1
kind: Service
metadata:
  name: redis-headless
  labels:
    app: redis-cluster
spec:
  clusterIP: None
  ports:
  - port: 6379
    name: client
  - port: 16379
    name: cluster
  selector:
    app: redis-cluster

Áp dụng và xác minh:

kubectl apply -f headless-svc.yaml
kubectl get svc redis-headless

5. StatefulSet cho cụm Redis

File redis-statefulset.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
  labels:
    app: redis-cluster
spec:
  serviceName: redis-headless
  replicas: 6
  podManagementPolicy: OrderedReady
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      labels:
        app: redis-cluster
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              topologyKey: topology.kubernetes.io/zone
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values: [redis-cluster]
      containers:
      - name: redis-server
        image: redis:7.2-alpine
        command: ["sh", "-c"]
        args:
        - |
          echo "Initializing Redis node $HOSTNAME";
          exec redis-server /etc/redis/redis-cluster.conf --requirepass mysecretpass
        ports:
        - containerPort: 6379
          name: client
        - containerPort: 16379
          name: cluster
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
        volumeMounts:
        - name: config-volume
          mountPath: /etc/redis
        - name: data-volume
          mountPath: /var/lib/redis
        livenessProbe:
          tcpSocket:
            port: 6379
          initialDelaySeconds: 30
          periodSeconds: 15
        readinessProbe:
          exec:
            command: ["redis-cli", "-a", "mysecretpass", "ping"]
          initialDelaySeconds: 15
          periodSeconds: 5
      volumes:
      - name: config-volume
        configMap:
          name: redis-cluster-config
          items:
          - key: redis-cluster.conf
            path: redis-cluster.conf
  volumeClaimTemplates:
  - metadata:
      name: data-volume
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "standard"
      resources:
        requests:
          storage: 5Gi

Triển khai và theo dõi trạng thái:

kubectl apply -f redis-statefulset.yaml
kubectl get pods -l app=redis-cluster -w

Sau khi tất cả các Pod ở trạng thái RunningReady, bạn có thể kết nối tới redis-cluster-0.redis-headless.default.svc.cluster.local:6379 để kiểm tra cấu hình cụm bằng lệnh CLUSTER NODES.

Thẻ: Kubernetes Redis statefulset PVC headless-service

Đăng vào ngày 30 tháng 6 lúc 19:49