必须用statefulset部署redis,因其提供稳定hostname(如redis-0.redis)、有序启停、独占pvc持久化存储及headless service支持gossip协议直连;deployment无法满足这些有状态需求。

直接用 StatefulSet 部署 Redis 是最稳妥的选择,尤其当你需要数据持久化、稳定网络标识或后续扩展为集群时。Deployment 适合临时测试,但无法保证节点身份和存储绑定,线上环境不推荐。
为什么必须用 StatefulSet 而不是 Deployment
Redis 实例之间有明确的拓扑依赖:主从关系、集群 gossip 通信、nodes.conf 文件中记录的节点 IP 和角色都要求每个 Pod 有固定 hostname(如 redis-0.redis)、可预测的启动顺序、以及独占且不随重建丢失的存储。Deployment 生成的 Pod 名称随机、无序重建、PVC 绑定不可控——这会导致:
-
redis-cli --cluster create初始化失败,因为节点发现不稳定 - 主从切换后从节点无法正确同步,
replicaof指向的旧 IP 已失效 - 集群模式下
nodes.conf中的地址残留,引发槽位分配冲突或连接拒绝
ConfigMap 配置里最容易被忽略的三个参数
很多配置模板直接复制官方默认值,但在 Kubernetes 环境中,以下三项不显式设置就会出问题:
-
bind 0.0.0.0:必须放开绑定,否则 Pod 内部只能本机访问,Service 流量进不来 -
protected-mode no:K8s 默认无密码访问,开启 protected-mode 会拒绝所有外部连接 -
cluster-config-file /data/nodes.conf:路径必须指向挂载的持久卷(/data),不能是/var/lib/redis/nodes.conf这类 tmpfs 路径,否则重启后集群元数据丢失
初始化 Redis Cluster 的时机很关键
StatefulSet 创建完 6 个 Pod 后,它们只是“运行着的 Redis 进程”,并未自动组成集群。你必须手动执行初始化命令,且必须在所有 Pod 就绪后再操作:
kubectl exec -it redis-0 -- redis-cli --cluster create \
$(kubectl get pods -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}:6379 {end}') \
--cluster-replicas 1
注意点:
- 不要用
localhost或 Service DNS 名(如redis-cluster.default.svc.cluster.local),gossip 协议依赖 Pod IP 直连 -
--cluster-replicas 1表示每主配一从,6 个 Pod 会自动分出 3 主 3 从 - 如果某 Pod 还没 Ready(比如
redis-2处于ContainerCreating),整个命令会卡住或失败
Headless Service 不是可选项,而是必需项
Redis Cluster 节点间靠 gossip 协议交换状态,每个节点必须能通过稳定 DNS 解析其他节点——这只能靠 Headless Service 实现:
apiVersion: v1
kind: Service
metadata:
name: redis-cluster
spec:
clusterIP: None
ports:
- port: 6379
name: client
- port: 16379
name: gossip
selector:
app: redis-cluster
这样 redis-0.redis-cluster、redis-1.redis-cluster 才能稳定解析到对应 Pod IP。普通 ClusterIP Service 只提供单点入口,无法支撑节点间直连通信。
真正麻烦的是 nodes.conf 的动态更新和跨节点 IP 同步——它不像数据库连接串那样能靠 ConfigMap 热加载,每次节点变更都得触发重写并重启容器,这点在滚动升级时特别容易翻车。











