【免费下载链接】charts
⚠️(OBSOLETE) Curated applications for Kubernetes
本篇技术指南以 helm/charts 仓库中 incubator/redis-cache/README.md 为骨架,结合该 Chart 的 values.yaml 与 templates/ 源码,系统讲解如何在 Kubernetes 中把 Redis 当作"纯内存缓存"使用,并借助 StatefulSet、Headless Service、PodDisruptionBudget 与哨兵工具 redis-sentinel-k8s 实现无持久化场景下的主从自动切换。读完本文,你将掌握该 Chart 的完整部署命令、配置参数含义、主从读写验证、故障演练流程以及性能基准测试方法,并能直接复制其中的命令与配置到自己的集群中复现验证。
一、背景:无持久化主从复制为何需要特殊处理
常规的 Redis 主从架构依赖 Redis Sentinel 或集群自带的故障转移机制。但当 Redis 被用作纯内存缓存(不开启持久化)时,会出现一个经典问题:Redis 官方在 Replication 文档 中明确指出——当主节点关闭持久化时,从节点在重启后无法安全地跟随主节点进行全量同步,因为主节点的数据只存在于内存中,重启后内存数据会丢失,进而可能导致从节点复制到不一致的数据。
在 Kubernetes 环境中,这个问题会被进一步放大:K8s 可能在哨兵们尚未探测到并达成共识之前,就先把故障的 master Pod 重启起来。也就是说,容器编排的重启速度可能快于哨兵故障检测的收敛速度,从而破坏主从数据的一致性。
incubator/redis-cache 这个 Chart 的定位,就是专门解决上述问题:它不使用传统的 Redis Sentinel 常驻进程,而是引入了一个特殊工具redis-sentinel-k8s(原项目为 redis-sentinel-micro,README 中提示可自行 fork),在 Pod 生命周期内完成 master/slave 角色协商与自动提升,绕开了"K8s 先于哨兵重启 master"的时间差隐患。
从仓库结构看,该 Chart 由以下文件组成:
- Chart.yaml(version 0.5.2,appVersion 4.0.12-alpine,
deprecated: true) - values.yaml(全部可配置参数)
- templates/ss.yaml(StatefulSet 主模板)
- templates/service.yaml(Headless Service)
- templates/pdb.yaml(PodDisruptionBudget)
- templates/_helpers.tpl(名称辅助模板)
- templates/NOTES.txt(安装后提示)
二、Chart 核心特性一览
README 对该 Chart 的能力做了如下概括:
| 特性 | 说明 |
|---|---|
| 极轻量镜像 | 使用redis:4.0.12-alpine(约 7MB),资源占用极低 |
| 自动从节点提升 | 使用redis-sentinel-k8s在 master 故障时自动完成 slave 提升,可 fork 定制 |
| 超快缓存 | 无持久化参与,读写性能高 |
| PodDisruptionBudget | 保证主动干扰(如节点维护)时仍有可用副本 |
| StatefulSet | 提供稳定的网络标识与有序部署/回收 |
| Anti-Affinity | 默认 hard 反亲和,副本尽量分布在不同节点 |
其中"7MB 镜像"与"自动 slave 提升"这两点在 Chart.yaml 的sources与 values.yaml 的microSentinel、makeSlave镜像配置中均有对应实现支撑。
三、架构设计:三副本与多容器协作
README 明确指出该 Chart 的默认形态是3 个副本、1 个 master + 2 个 slave。这一设计通过 templates/ss.yaml 中的 StatefulSet 模板落地,每个 Pod 内实际包含 3 个不同职责的容器/初始化容器:
3.1 主容器 redis
- name: redis image: {{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }} imagePullPolicy: {{ .Values.redis.image.pullPolicy }} ports: - containerPort: {{ .Values.service.port }} name: {{ .Values.service.name }} resources: {{ toYaml .Values.redis.resources | indent 12 }}默认使用redis:4.0.12-alpine镜像,暴露6379端口,内存限制与请求均为 128Mi(见 values.yaml 第 13-17 行)。
3.2 初始化容器 sentinel-micro
initContainers: - name: sentinel-micro image: {{ .Values.microSentinel.image.repository }}:{{ .Values.microSentinel.image.tag }} args: ["-service", {{ template "redis-cache.fullname" . }}] env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumeMounts: - name: config mountPath: /configsentinel-micro是 init container,默认镜像为dhilipkumars/redis-sentinel-k8s:0.1.0。它在 Pod 真正启动 Redis 之前运行,通过-service参数接收本 Chart 的 fullname,再结合POD_NAMESPACE环境变量解析集群内可用的端点列表,探测当前谁是 master、谁是 slave,并完成角色配置。README 中的故障演练日志(见第六节)展示了它的典型执行流程:
I0412 18:07:08.633263 1 redis_sentinel_k8s.go:368] Available endpoints are [rd-dev-2.rd-dev.default.svc.cluster.local rd-dev-1.rd-dev.default.svc.cluster.local] I0412 18:07:08.633392 1 redis_sentinel_k8s.go:194] Processing rd-dev-2.rd-dev.default.svc.cluster.local I0412 18:07:08.633446 1 redis_sentinel_k8s.go:194] Processing rd-dev-1.rd-dev.default.svc.cluster.local I0412 18:07:08.645222 1 redis_sentinel_k8s.go:382] OldMaster=<nil> NewMaster=&{rd-dev-1.rd-dev.default:6379 ...} I0412 18:07:08.646876 1 redis_sentinel_k8s.go:398] New Master is rd-dev-1.rd-dev.default:6379, All the slaves are re-configured to replicate from this I0412 18:07:08.647040 1 redis_sentinel_k8s.go:421] Redis-Sentinal-micro Finished3.3 边车容器 make-slave
- name: make-slave image: {{ .Values.makeSlave.image.repository }}:{{ .Values.makeSlave.image.tag }} env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace volumeMounts: - name: config mountPath: /config默认镜像为dhilipkumars/mk-redis-slave:0.1.0。从命名与挂载方式看,它的职责是确保"非 master 的本地实例始终作为 slave 跟随当前 master 复制",与 sentinel-micro 一起构成完整的角色收敛闭环。
3.4 共享配置卷
volumes: - name: config emptyDir: {}三个容器共享同一个emptyDir配置卷(挂载到/config),用于在容器间传递角色协商结果。
四、关键模板机制解读
4.1 命名规则(_helpers.tpl)
incubator/redis-cache/templates/_helpers.tpl 定义了 Chart 内统一使用的名称:
{{- define "redis-cache.fullname" -}} {{- $name := default .Chart.Name .Values.nameOverride -}} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} {{- end -}}即 fullname =<release 名>-<chart 名>(当前 chart 名为redis-cache),并截断到 63 字符以满足 DNS 命名规范。注意:README 中的安装输出(如rd-dev、rd-dev-0)来自 2017 年早期版本的渲染结果;按当前模板,以 release 名dev安装时生成的资源名将是dev-redis-cache、Pod 名为dev-redis-cache-0等,验证命令时请以实际部署名称为准。
4.2 Headless Service(service.yaml)
templates/service.yaml 创建的是clusterIP: None的 Headless Service,关键细节是注解:
annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"该注解允许 Service 在 Pod 未就绪时也填充 Endpoints,使每个 StatefulSet 副本都能通过<pod>.<service>.<namespace>的 DNS 名称互相寻址——这正是 sentinel-micro 在 init 阶段解析端点、以及各副本之间建立复制关系的基础。
4.3 PodDisruptionBudget(pdb.yaml)
templates/pdb.yaml 声明了minAvailable: 2(默认值,见 values.yaml 第 49-50 行),保证集群在进行节点维护等自愿性干扰时,至少保留 2 个副本可用,避免缓存服务完全中断。
4.4 反亲和与优雅终止(ss.yaml)
templates/ss.yaml 中:
- 第 26-44 行实现反亲和:
antiAffinity: "hard"时使用requiredDuringSchedulingIgnoredDuringExecution,以kubernetes.io/hostname为拓扑键强制副本分散到不同节点;"soft"时降级为preferredDuringSchedulingIgnoredDuringExecution(权重 5),尽量分散但不强制。 - 第 25 行设置
terminationGracePeriodSeconds: 60,给 Redis 与角色收敛留出优雅退出时间。
五、配置参数全解(values.yaml)
incubator/redis-cache/values.yaml 是该 Chart 的唯一配置入口,全部参数如下:
| 参数 | 默认值 | 作用 | 对应模板 |
|---|---|---|---|
antiAffinity | "hard" | 反亲和强度:hard(强制)或soft(尽量) | ss.yaml 第 26-44 行 |
replicaCount | 3 | 副本数(默认 1 master + 2 slave) | ss.yaml 第 16 行 |
redis.image.repository | redis | Redis 镜像仓库 | ss.yaml 第 63 行 |
redis.image.tag | 4.0.12-alpine | Redis 镜像标签 | ss.yaml 第 63 行 |
redis.image.pullPolicy | IfNotPresent | 拉取策略 | ss.yaml 第 64 行 |
redis.resources.limits.memory | 128Mi | Redis 内存上限 | ss.yaml 第 69 行 |
redis.resources.requests.memory | 128Mi | Redis 内存请求 | ss.yaml 第 69 行 |
microSentinel.image.repository | dhilipkumars/redis-sentinel-k8s | sentinel-micro 镜像 | ss.yaml 第 47 行 |
microSentinel.image.tag | 0.1.0 | sentinel-micro 标签 | ss.yaml 第 47 行 |
microSentinel.resources | {} | sentinel-micro 资源限制(默认不设) | ss.yaml 第 51 行 |
makeSlave.image.repository | dhilipkumars/mk-redis-slave | make-slave 镜像 | ss.yaml 第 71 行 |
makeSlave.image.tag | 0.1.0 | make-slave 标签 | ss.yaml 第 71 行 |
makeSlave.resources | {} | make-slave 资源限制(默认不设) | ss.yaml 第 74 行 |
service.name | rd-port | 端口名称 | service.yaml / ss.yaml |
service.port | 6379 | Redis 服务端口 | service.yaml / ss.yaml |
podDisruptionBudget.minAvailable | 2 | PDB 最小可用副本数 | pdb.yaml 第 11 行 |
从源码结构看,microSentinel.resources与makeSlave.resources在 values.yaml 中以注释形式预留了cpu/memory的示例(如cpu: 10m、memory: 20Mi),需要时可取消注释并按需调整;redis.resources则默认即有 128Mi 的内存限制,适合小型缓存场景。
六、安装部署与资源清单解读
6.1 前置条件
- Kubernetes 1.10+(README 明确声明)
- 已配置好 Helm(README 中的命令为 Helm 2.x 时代用法,其中
-n用于指定 release 名称)
6.2 安装命令
$ helm install -n dev incubator/redis-cache/README 记录的成功安装输出如下:
NAME: dev LAST DEPLOYED: Wed Apr 12 23:25:56 2017 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE rd-dev None <none> 6379/TCP 0s ==> policy/v1beta1/PodDisruptionBudget NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE rd-dev 2 0 0s ==> apps/v1beta1/StatefulSet NAME DESIRED CURRENT AGE rd-dev 3 0 0s安装会依次创建:
- Headless Service(
Cluster-IP: None,端口 6379)——对应 templates/service.yaml; - PodDisruptionBudget(
MIN-AVAILABLE: 2)——对应 templates/pdb.yaml; - StatefulSet(
DESIRED: 3)——对应 templates/ss.yaml。
版本差异提示:上述输出中的
apps/v1beta1、policy/v1beta1是早期 Kubernetes/Helm 版本的渲染结果;当前仓库 templates/ss.yaml 第 1 行已使用apiVersion: apps/v1,templates/pdb.yaml 使用policy/v1beta1,实际部署时以目标集群支持的 API 版本为准。
6.3 安装后提示
安装完成后,Chart 内置的 NOTES.txt 会打印查找 master 的命令:
kubectl exec -i -t rd-dev-0 -c redis -- redis-cli -h rd-dev-0.rd-dev.default -p 6379 info replication(按当前命名模板,可替换为kubectl exec -i -t <release>-redis-cache-0 -c redis -- redis-cli -h <release>-redis-cache-0.<release>-redis-cache.<namespace> -p 6379 info replication。)
6.4 查看副本就绪状态
$ kubectl get pods NAME READY STATUS RESTARTS AGE rd-dev-0 2/2 Running 0 57s rd-dev-1 2/2 Running 0 41s rd-dev-2 2/2 Running 0 29s每个 Pod 显示2/2,对应redis与make-slave两个常驻容器(sentinel-micro 作为 init container 已执行完毕)。
七、验证主从关系与缓存读写
7.1 确认当前 master
$ kubectl exec -i -t rd-dev-0 -c redis -- redis-cli -h rd-dev-0.rd-dev.default -p 6379 info replication # Replication role:master connected_slaves:2 slave0:ip=10.244.2.18,port=6379,state=online,offset=29,lag=0 slave1:ip=10.244.1.16,port=6379,state=online,offset=29,lag=0 master_repl_offset:29 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:28关键字段说明:
role:master:当前副本是主节点;connected_slaves:2:已有 2 个从节点在线;slave0/slave1:从节点 IP、端口、复制状态与offset(偏移量一致说明复制是同步的);master_repl_offset:主节点当前复制偏移量。
7.2 写入数据并跨副本读取
向 master 写入一个键:
$ kubectl exec -i -t rd-dev-0 -c redis -- redis-cli -h rd-dev-0.rd-dev.default -p 6379 set foo bar OK从任意 slave 读取(这里以rd-dev-2为例),验证复制已生效:
$ kubectl exec -i -t rd-dev-0 -c redis -- redis-cli -h rd-dev-2.rd-dev.default -p 6379 get foo "bar"八、故障演练:杀掉 master 后的自动提升
这是该 Chart 的核心价值所在——验证 master 故障后,数据不丢失、角色自动收敛。
8.1 删除 master Pod
$ kubectl delete po/rd-dev-0 pod "rd-dev-0" deleted8.2 观察 sentinel-micro 的日志
等待 Kubernetes 将rd-dev-0重新拉起后,查看其 init 容器日志:
$ kubectl logs rd-dev-0 sentinel-micro I0412 18:07:08.633263 1 redis_sentinel_k8s.go:368] Available endpoints are [rd-dev-2.rd-dev.default.svc.cluster.local rd-dev-1.rd-dev.default.svc.cluster.local] I0412 18:07:08.633392 1 redis_sentinel_k8s.go:194] Processing rd-dev-2.rd-dev.default.svc.cluster.local I0412 18:07:08.633446 1 redis_sentinel_k8s.go:194] Processing rd-dev-1.rd-dev.default.svc.cluster.local R=&{ slave -1 7 937 rd-dev-0.rd-dev.default 6379 100 false <nil>} R=&{ slave -1 7 937 rd-dev-0.rd-dev.default 6379 100 false <nil>} I0412 18:07:08.645222 1 redis_sentinel_k8s.go:382] OldMaster=<nil> NewMaster=&{rd-dev-1.rd-dev.default:6379 slave -1 7 937 rd-dev-0.rd-dev.default 6379 100 false 0xc42000e300} I0412 18:07:08.646876 1 redis_sentinel_k8s.go:398] New Master is rd-dev-1.rd-dev.default:6379, All the slaves are re-configured to replicate from this I0412 18:07:08.647040 1 redis_sentinel_k8s.go:421] Redis-Sentinal-micro Finished日志解读:
Available endpoints are [...]:从 Headless Service 解析出可用端点;OldMaster=<nil> NewMaster=...:原 master 已不可用,选举出新的 master;New Master is rd-dev-1.rd-dev.default:6379, All the slaves are re-configured to replicate from this:rd-dev-1 被提升为新 master,其余副本全部重新配置为从它复制;Redis-Sentinal-micro Finished:本次角色收敛完成。
8.3 验证数据在 master 重启后保留
$ kubectl exec -i -t rd-dev-0 -c redis -- redis-cli -h rd-dev-0.rd-dev.default -p 6379 get foo "bar"关键点:即使原 masterrd-dev-0被删除并重启,键foo依然可读——因为数据早已通过主从复制存在于其他副本中,且新的 master 已经接管写入服务。这正是"无持久化 + 哨兵式自动提升"方案与裸 Redis 无持久化部署的本质区别。
九、性能基准:持久化 vs 非持久化
README 提供了一个快速基准对比,说明开启持久化时写入速度明显下降(文档中记录:写操作至少慢 3 倍)。基准命令在任意副本内执行,通过 Pod 间 DNS 直连进行压力测试:
$ k exec -i -t ${REPLICA-NAME} -c redis -- redis-benchmark -q -h ${REPLICA-NAME}.${POD-NAME}.${NAMESPACE} -p 6379 -t set,get -n 100000 -d 100 -r 1000000-t set,get:只测 SET 与 GET;-n 100000:总请求数 10 万;-d 100:数据大小为 100 字节;-r 1000000:随机键范围 100 万。
开启持久化(persistence enabled):
SET: 22026.43 requests per second GET: 76161.46 requests per second关闭持久化(without persistence):
SET: 60060.06 requests per second GET: 89285.71 requests per second结果解读:
| 操作 | 开启持久化 | 关闭持久化 | 提升幅度 |
|---|---|---|---|
| SET | 22026 req/s | 60060 req/s | 约 2.7 倍 |
| GET | 76161 req/s | 89285 req/s | 约 1.2 倍 |
可见 RDB/AOF 持久化对写入路径的损耗远大于读取路径,这正是该 Chart 选择"纯内存、无持久化"定位的性能依据:在可容忍缓存丢失的业务场景中,用极轻量镜像 + 主从自动提升换取接近 3 倍的写入吞吐。
十、运维注意事项与弃用说明
10.1 缩容前必须确认 master 不在下线名单
README 特别强调了一条缩容纪律:
Care should be taken when you scale down the number of replicas of this statefulset. Please make sure that current redis-master is not amongto be scaled downreplicas.
即:对 StatefulSet 执行缩容前,务必确认当前 master 不在即将被缩掉的副本之列。StatefulSet 缩容会按序号从大到小删除 Pod,如果 master 恰好序号最大(如rd-dev-2是 master),直接缩容会导致 master 被删除,可能引发不必要的角色切换甚至数据可用性窗口。正确做法是:先通过info replication定位 master,必要时先把 master 的角色迁移到保留的副本上,再执行缩容。
10.2 Chart 与仓库的弃用状态
需要明确告知读者当前项目状态,避免误用于生产环境:
- 本仓库(helm/charts 的镜像)自2020 年 11 月 13 日起进入归档状态,Chart 不再更新(见 incubator/redis-cache/README.md 顶部的 Archive Notice);
- Chart.yaml 中
deprecated: true,README 亦有 DEPRECATION NOTICE; - 该 Chart 的镜像版本停留在
redis:4.0.12-alpine(2017-2018 年代),且依赖的dhilipkumars/redis-sentinel-k8s属于第三方工具,建议仅将其作为设计思路与实现参考,在生产环境迁移到官方 Redis Sentinel、Redis Cluster 或 Bitnami 等仍在维护的方案。
总结
incubator/redis-cache 是一个"小而精"的参考实现:它用StatefulSet + Headless Service + PDB + 反亲和构建高可用骨架,用sentinel-micro(init container)在 Pod 启动前完成 master 探测与选举,用make-slave(sidecar)保证其余副本持续跟随新 master,从而在完全关闭持久化的前提下依然具备主从自动切换与数据保留能力。README 提供的安装命令、验证命令、故障演练流程与基准测试方法均可在集群中直接复现;而仓库中的 values.yaml 与 templates/ 则为理解"参数如何落到 Kubernetes 资源"提供了完整的源码级证据。对于想要在自己的缓存体系中落地"无持久化 + 哨兵式自动提升"方案的读者,这是一个非常值得研读的起点。
【免费下载链接】charts
⚠️(OBSOLETE) Curated applications for Kubernetes
相关推荐
Redis Object Cache:基于Redis的WordPress缓存解决方案
Redis Object Cache:基于Redis的WordPress缓存解决方案 项目基础介绍 Redis Object Cache 是由 rhubarbg
ROLL多任务RL训练指南:数学、编程、通用推理全流程实战
ROLL多任务RL训练指南:数学、编程、通用推理全流程实战 ROLL(GitHub 加速计划)是一个高效且用户友好的大模型强化学习训练框架,支持数学推理、代码生
express缓存策略:Redis和内存缓存优化方案
express缓存策略:Redis和内存缓存优化方案 前言:为什么需要缓存优化? 在现代Web应用开发中,性能优化是每个开发者必须面对的挑战。当你的Expres
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考