Kubernetes 构建 Redis 集群
一、问题分析
本质上来说,在 k8s 上部署一个 redis 集群和部署一个普通应用没有什么太大的区别,但需要注意下面几个问题:
Redis 是一个有状态应用
这是部署 redis 集群时我们最需要注意的问题,当我们把 redis 以 pod 的形式部署在 k8s 中时,每个 pod 里缓存的数据都是不一样的,而且 pod 的 IP 是会随时变化,这时候如果使用普通的 deployment 和 service 来部署 redis-cluster 就会出现很多问题,因此需要改用 StatefulSet + Headless Service 来解决
数据持久化
redis 虽然是基于内存的缓存,但还是需要依赖于磁盘进行数据的持久化,以便服务出现问题重启时可以恢复已经缓存的数据。在集群中,我们需要使用共享文件系统 + PV(持久卷)的方式来让整个集群中的所有 pod 都可以共享同一份持久化储存
二、概念介绍
在开始之前先来详细介绍一下几个概念和原理。
1、Headless Service
简单的说,Headless Service 就是没有指定 Cluster IP 的 Service,相应的,在 k8s 的 dns 映射里,Headless Service 的解析结果不是一个 Cluster IP,而是它所关联的所有 Pod 的 IP 列表
2、StatefulSet
StatefulSet
是 k8s 中专门用于解决有状态应用部署的一种资源,总的来说可以认为它是Deployment/RC
的一个变种,它有以下几个特性:
StatefulSet 管理的每个 Pod 都有唯一的文档/网络标识,并且按照数字规律生成,而不是像 Deployment 中那样名称和 IP 都是随机的(比如 StatefulSet 名字为 redis,那么 pod 名就是 redis-0, redis-1 ...)
StatefulSet 中 ReplicaSet 的启停顺序是严格受控的,操作第 N 个 pod 一定要等前 N-1 个执行完才可以
StatefulSet 中的 Pod 采用稳定的持久化储存,并且对应的 PV 不会随着 Pod 的删除而被销毁
另外需要说明的是,StatefulSet 必须要配合 Headless Service 使用,它会在 Headless Service 提供的 DNS 映射上再加一层,最终形成精确到每个 pod 的域名映射,格式如下:
有了这个映射,就可以在配置集群时使用域名替代 IP,实现有状态应用集群的管理
三、方案
借助 StatefulSet 和 Headless Service,集群的部署方案设计如下(图片来自参考文章):
配置步骤大概罗列如下:
配置共享文件系统 NFS
创建 PV 和 PVC
创建 ConfigMap
创建 Headless Service
创建 StatefulSet
初始化 redis 集群
实际操作
为了简化复杂度,这次先不配置 PV 和 PVC,直接通过普通 Volume 的方式来挂载数据。在K8s上搭建Mysql集群
1、创建 ConfigMap
先创建redis.conf
配置文件
然后kubectl create configmap redis-conf --from-file=redis.conf
来创建 ConfigMap
2、创建 HeadlessService
3、创建 StatefulSet
4、初始化 redis 集群
StatefulSet 创建完毕后,可以看到 6 个 pod 已经启动了,但这时候整个 redis 集群还没有初始化,需要使用官方提供的redis-trib
工具。
我们当然可以在任意一个 redis 节点上运行对应的工具来初始化整个集群,但这么做显然有些不太合适,我们希望每个节点的职责尽可能地单一,所以最好单独起一个 pod 来运行整个集群的管理工具。
在这里需要先介绍一下redis-trib
,它是官方提供的 redis-cluster 管理工具,可以实现 redis 集群的创建、更新等功能,在早期的 redis 版本中,它是以源码包里redis-trib.rb
这个 ruby 脚本的方式来运作的(pip 上也可以拉到 python 版本,但我运行失败),现在(我使用的5.0.3
)已经被官方集成进redis-cli
中。
开始初始化集群,首先在 k8s 上创建一个 ubuntu 的 pod,用来作为管理节点:
进入 pod 内部先安装一些工具,包括wget
,dnsutils
,然后下载和安装 redis:
编译完毕后redis-cli
会被放置在src
目录下,把它放进/usr/local/bin
中方便后续操作
接下来要获取已经创建好的 6 个节点的 host ip,可以通过nslookup
结合 StatefulSet 的域名规则来查找,举个例子,要查找redis-app-0
这个 pod 的 ip,运行如下命令:
172.17.0.10
就是对应的 ip。这次部署我们使用 0,1,2 作为 Master 节点;3,4,5 作为 Slave 节点,先运行下面的命令来初始化集群的 Master 节点:
然后给他们分别附加对应的 Slave 节点,这里的cluster-master-id
在上一步创建的时候会给出:
集群初始化后,随意进入一个节点检查一下集群信息:
至此,集群初始化完毕,我们进入一个节点来试试,注意在集群模式下redis-cli
必须加上-c
参数才能够访问其他节点上的数据:
5、创建 Service
现在进入 redis 集群中的任意一个节点都可以直接进行操作了,但是为了能够对集群其他的服务提供访问,还需要建立一个 service 来实现服务发现和负载均衡(注意这里的 service 和我们之前创建的 headless service 不是一个东西)
yaml 文件如下:
部署完做个测试:
很简单,到这里所有的工作就完毕了~
版权声明: 本文为 InfoQ 作者【CTO技术共享】的原创文章。
原文链接:【http://xie.infoq.cn/article/642977d7b1a0e6d70a19c66f0】。未经作者许可,禁止转载。
评论