Skip to content

Redis on Kubernetes 部署與維運

在 Kubernetes 與 AKS 上部署 Redis Master-Replica 架構,涵蓋 Bitnami Helm Chart 安裝、官方 Image StatefulSet 部署、LoadBalancer 暴露、備份還原與 Standalone 快速啟動。

概述

Redis 在 Kubernetes 上最常見的做法是透過 Bitnami Helm Chart 部署 Master-Replica 架構,Master 負責讀寫,Replicas 提供唯讀分流。Helm Chart 會自動建立 PVC,但在升級或重建時需要注意:PVC 不會被自動刪除,需要手動管理,這個特性在需要保留資料的升級場景中反而是一個優勢(可利用既有 PVC 進行資料繼承)。

對外暴露 Redis 服務的方式隨著部署環境演進:本地 K8s 使用 NodePort,AKS 環境則建立獨立的 Azure Internal LoadBalancer Service,讓 Master 與 Replicas 各自擁有固定的內部 IP 端點。

核心內容

Bitnami Helm Chart 關鍵參數

參數說明
auth.passwordRedis 密碼
master.disableCommands停用危險指令(如 FLUSHALL),留空 '' 表示不停用任何指令
replica.disableCommandsReplicas 同步停用的危險指令
global.storageClassStorageClass(本地 K8s 用 nfs-client,AKS 用 managed-csi-premium
master.persistence.sizeMaster PVC 大小
replica.persistence.sizeReplicas PVC 大小
replica.replicaCountReplica 數量(建議至少 1)
commonConfigurationRedis 設定(如 databases 128
master.persistence.existingClaim指定既有 PVC(用於資料繼承升級)

重要: master.disableCommandsreplica.disableCommands 必須保持一致,否則會導致資料不同步。

備份與還原策略

Method 1:匯出 dump.rdb 再還原

適用於跨版本升級(版本差異太大無法 upgrade 時):

  1. 在 redis-cli 中執行 save 產生 /data/dump.rdb
  2. kubectl cp 將檔案複製到本地(加 --retries=5 提高成功率)
  3. md5sum 確認複製完整性
  4. 建立臨時 Pod 掛載目標 PVC,將 dump.rdb 複製進去
  5. 重新安裝 Redis 並掛載該 PVC

Method 2:砍掉重裝,直接利用原有 PVC

更簡潔的做法,透過 master.persistence.existingClaim 參數直接繼承既有 PVC 的資料,不需要手動搬移檔案。注意:Replica PVC 若不繼承,需先手動刪除,讓 Helm 重新建立空的 Replica PVC。

叢集內部連線

用途DNSPort
讀寫(Master)redis-master.redis-system.svc.cluster.local6379
唯讀(Replicas)redis-replicas.redis-system.svc.cluster.local6379

官方 Image StatefulSet 部署(AKS,2026/02)

當需要從 Bitnami Image 遷移至官方 Redis Image,或需要更精細控制 StatefulSet 配置時,可改用官方 redis Image 直接撰寫 StatefulSet YAML,不依賴 Helm Chart。

架構重點:

  • Master 使用預先建立的 PVC(redis-master-0),保留既有資料
  • Replica 使用 VolumeClaimTemplate 自動建立新 PVC
  • Master 與 Replica 的 Internal LoadBalancer 共用同一個 IP10.30.196.79),透過不同 port 區分(Master: 6379,Replica: 6380)
  • initContainer 負責修正 UID:從 Bitnami 的 1001 → 官方 Image 的 999
  • Redis 設定(密碼、databasesappendonly、禁用 FLUSHALL)透過 ConfigMap 注入

Standalone 輕量部署

對於不需要 Master-Replica 架構的場景(如單一應用的快取需求),可直接以 redis:latest 映像搭配簡單的 Deployment + Service 快速建立。資料持久化透過 PVC 實現,密碼以啟動參數 --requirepass 傳入。

關鍵要點

  • PVC 在 helm uninstall 後不會自動刪除,需手動清理或利用此特性繼承資料
  • AKS 環境最新作法(2023/08):Master 與 Replicas 各自建立獨立的 Internal LoadBalancer
  • 新版 Helm Chart 無法透過 --set 直接設定 NodePort,需自行建立 Service YAML
  • 指定 resources.requests.memory 避免 OOM Kill(預設值可能過低)
  • commonConfiguration='databases 128'(或 256)可擴充資料庫數量上限
  • 從 Bitnami 遷移至官方 Image 時,需 initContainer 修正資料目錄 UID(1001 → 999)
  • FLUSHALL 可在 ConfigMap 的 rename-command 設為空字串予以禁用(等同關閉)

實際應用

Redis 在 AKS 上透過 Internal LoadBalancer 提供固定 IP 端點(Master: 10.30.196.79,Replicas: 10.30.196.80),應用程式依據讀寫需求連接不同端點實現讀寫分離。Redis Exporter 部署後,Prometheus 透過叢集內部 DNS 抓取指標,詳見 Redis Exporter 部署

部署設定參考

以下為實際部署時使用的完整設定,供日後查詢與複製使用。

環境參數

項目
Namespaceredis-system
密碼Bed200@2022
databases128(K8s)/ 256(AKS 升級後)
Master PVC12Gi(AKS)
Replica PVC12Gi(AKS)
StorageClassnfs-client(K8s)/ managed-csi-premium(AKS)
Chart 版本17.10.3(2023-05 安裝)
App 版本Redis 7.0.11

安裝指令

K8s(NodePort,2023/05)

bash
helm install --namespace redis-system redis \
  --set auth.password=Bed200@2022,\
master.disableCommands='',\
replica.disableCommands='',\
global.storageClass="nfs-client",\
master.service.type=NodePort,\
master.service.nodePorts.redis=30100,\
replica.service.type=NodePort,\
replica.service.nodePorts.redis=30101,\
commonConfiguration='databases 128' \
  bitnami/redis

AKS(2023/09)

bash
helm install redis bitnami/redis --namespace redis-system \
  --set auth.password=Bed200@2022,\
master.disableCommands='',\
replica.disableCommands='',\
global.storageClass="managed-csi-premium",\
master.persistence.size=12Gi,\
replica.persistence.size=12Gi,\
replica.replicaCount=1,\
replica.resources.requests.memory=2Gi,\
master.resources.requests.memory=2Gi,\
commonConfiguration='databases 128'

AKS Upgrade(2024/04)

bash
helm upgrade redis bitnami/redis \
  --namespace redis-system \
  --reuse-values \
  --set master.resources.requests.memory=16Gi \
  --set replica.resources.requests.memory=8Gi

利用既有 PVC 重裝(AKS 2025/02)

bash
helm install redis bitnami/redis --namespace redis-system \
  --set auth.password=Bed200@2022,\
master.disableCommands={'FLUSHALL'},\
replica.disableCommands={'FLUSHALL'},\
master.persistence.existingClaim="redis-data-redis-master-0",\
replica.persistence.existingClaim="redis-data-redis-replicas-0",\
replica.replicaCount=1,\
replica.resources.requests.memory=8Gi,\
master.resources.requests.memory=16Gi,\
commonConfiguration='databases 256'

利用既有 PVC 重裝(K8s 2025/09)

bash
helm install --namespace redis-system redis \
  --set auth.password=Bed200@2022,\
master.disableCommands={'FLUSHALL'},\
replica.disableCommands={'FLUSHALL'},\
global.storageClass="nfs-client",\
master.persistence.existingClaim="redis-data-redis-k8s-master-0",\
replica.replicaCount=1,\
replica.resources.requests.memory=8Gi,\
master.resources.requests.memory=16Gi,\
commonConfiguration='databases 256' \
  bitnami/redis

自訂 LoadBalancer Service(AKS)

yaml
apiVersion: v1
kind: Service
metadata:
  name: redis-master-loadbalancer
  namespace: redis-system
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.79
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/component: master
    app.kubernetes.io/instance: redis
    app.kubernetes.io/name: redis
  ports:
    - protocol: TCP
      port: 6379
      targetPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis-replicas-loadbalancer
  namespace: redis-system
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.80
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/component: replica
    app.kubernetes.io/instance: redis
    app.kubernetes.io/name: redis
  ports:
    - protocol: TCP
      port: 6379
      targetPort: 6379
角色Internal LB IPPort
Master10.30.196.796379
Replicas10.30.196.806379

操作指令

bash
# 取得密碼
export REDIS_PASSWORD=$(kubectl get secret --namespace redis-system redis \
  -o jsonpath="{.data.redis-password}" | base64 -d)

# 啟動 Redis client Pod
kubectl run --namespace redis-system redis-client \
  --restart='Always' \
  --env REDIS_PASSWORD=$REDIS_PASSWORD \
  --image docker.io/bitnami/redis:7.0.12-debian-11-r2 \
  --command -- sleep infinity

# 進入 Pod
kubectl exec --tty -i redis-client --namespace redis-system -- bash

# 連線 Master
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-master

# 連線 Replicas
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-replicas

官方 Image StatefulSet 部署(AKS 2026/02)

環境參數

項目
Namespaceredis-system
Imageredis:8.6.0-trixie
密碼Bed200@2022
Master PVCredis-master-0(預先建立)
Replica PVC50Gi(VolumeClaimTemplate,managed-csi-premium
Master Memory Request16Gi
Replica Memory Request8Gi
Master LB IP:Port10.30.196.79:6379
Replica LB IP:Port10.30.196.79:6380

完整 YAML 清單

yaml
# 1. ConfigMap — 共用 Redis 設定
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-config
  namespace: redis-system
data:
  redis-common.conf: |
    databases 256
    appendonly yes
    protected-mode no
    rename-command FLUSHALL ""
    requirepass Bed200@2022
    masterauth Bed200@2022

---

# 2. Headless Service — Master 識別用
apiVersion: v1
kind: Service
metadata:
  name: redis-master-svc
  namespace: redis-system
spec:
  clusterIP: None
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    app: redis
    role: master

---

# 3. ClusterIP Service — Replica 讀取
apiVersion: v1
kind: Service
metadata:
  name: redis-replica-svc
  namespace: redis-system
spec:
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    app: redis
    role: replica

---

# 4. StatefulSet — Redis Master
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: aks-redis-master
  namespace: redis-system
spec:
  serviceName: "redis-master-svc"
  replicas: 1
  selector:
    matchLabels:
      app: redis
      role: master
  template:
    metadata:
      labels:
        app: redis
        role: master
    spec:
      initContainers:
      - name: fix-bitnami-migration
        image: busybox
        command:
        - sh
        - -c
        - |
          chown -R 999:999 /data
        volumeMounts:
        - name: redis-data
          mountPath: /data
      containers:
      - name: redis
        image: redis:8.6.0-trixie
        command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
        env:
        - name: REDIS_PASSWORD
          value: "Bed200@2022"
        resources:
          requests:
            memory: 16Gi
            cpu: 500m
        ports:
        - containerPort: 6379
        volumeMounts:
        - name: redis-data
          mountPath: /data
        - name: config
          mountPath: /usr/local/etc/redis/redis.conf
          subPath: redis-common.conf
      volumes:
      - name: config
        configMap:
          name: redis-config
      - name: redis-data
        persistentVolumeClaim:
          claimName: redis-master-0

---

# 5. StatefulSet — Redis Replica
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: aks-redis-replica
  namespace: redis-system
spec:
  serviceName: "redis-replica-svc"
  replicas: 1
  selector:
    matchLabels:
      app: redis
      role: replica
  template:
    metadata:
      labels:
        app: redis
        role: replica
    spec:
      containers:
      - name: redis
        image: redis:8.6.0-trixie
        command: ["redis-server", "/usr/local/etc/redis/redis.conf", "--replicaof", "redis-master-svc", "6379"]
        resources:
          requests:
            memory: 8Gi
            cpu: 500m
        ports:
        - containerPort: 6379
        volumeMounts:
        - name: redis-data
          mountPath: /data
        - name: config
          mountPath: /usr/local/etc/redis/redis.conf
          subPath: redis-common.conf
      volumes:
      - name: config
        configMap:
          name: redis-config
  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "managed-csi-premium"
      resources:
        requests:
          storage: 50Gi

---

# 6. Internal LoadBalancer — Master(Port 6379)
apiVersion: v1
kind: Service
metadata:
  name: aks-redis-master-loadbalancer
  namespace: redis-system
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.79
spec:
  type: LoadBalancer
  selector:
    app: redis
    role: master
  ports:
    - protocol: TCP
      port: 6379
      targetPort: 6379

---

# 7. Internal LoadBalancer — Replica(Port 6380)
apiVersion: v1
kind: Service
metadata:
  name: aks-redis-replica-loadbalancer
  namespace: redis-system
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.79
spec:
  type: LoadBalancer
  selector:
    app: redis
    role: replica
  ports:
    - protocol: TCP
      port: 6380
      targetPort: 6379

Standalone 快速啟動(Server 版本,2025/06)

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wes-redis-pvc
  namespace: ingress-basic
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: managed-csi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wes-redis
  namespace: ingress-basic
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wes-redis
  template:
    metadata:
      labels:
        app: wes-redis
    spec:
      securityContext:
        fsGroup: 999
      containers:
      - name: redis
        image: redis
        ports:
        - containerPort: 6379
        args:
          - "--requirepass"
          - "wes@CuIce"
        volumeMounts:
        - name: redis-data
          mountPath: /data
      volumes:
      - name: redis-data
        persistentVolumeClaim:
          claimName: wes-redis-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: wes-redis
  namespace: ingress-basic
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.30.196.79
spec:
  ports:
  - port: 3379
    targetPort: 6379
  selector:
    app: wes-redis
  type: LoadBalancer
項目
Namespaceingress-basic
Passwordwes@CuIce
Internal LB IP10.30.196.79
外部 Port3379
容器 Port6379

相關概念

來源