一、问题分析

本质上来说在 k8s 上部署一个 redis 集群和部署一个普通应用没有什么太大的区别,但需要注意下面几个问题:

  1. Redis 是一个有状态应用:这是部署 redis 集群时我们最需要注意的问题,当我们把 redis 以 pod 的形式部署在 k8s 中时,每个 pod 里缓存的数据都是不一样的,而且 pod 的 IP 是会随时变化,这时候如果使用普通的 deployment 和 service 来部署 redis-cluster 就会出现很多问题,因此需要改用 StatefulSet + Headless Service 来解决。

  2. 数据持久化: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 的一个变种,它有以下几个特性:

  1. StatefulSet 管理的每个 Pod 都有唯一的文档/网络标识,并且按照数字规律生成,而不是像 Deployment 中那样名称和 IP 都是随机的(比如 StatefulSet 名字为 redis,那么 pod 名就是 redis-0, redis-1 ...)

  2. StatefulSet 中 ReplicaSet 的启停顺序是严格受控的,操作第 N 个 pod 一定要等前 N-1 个执行完才可以

  3. StatefulSet 中的 Pod 采用稳定的持久化储存,并且对应的 PV 不会随着 Pod 的删除而被销毁

另外需要说明的是,StatefulSet 必须要配合 Headless Service 使用,它会在 Headless Service 提供的 DNS 映射上再加一层,最终形成精确到每个 pod 的域名映射,格式如下:

$(podname).$(headless service name)

有了这个映射,就可以在配置集群时使用域名替代 IP,实现有状态应用集群的管理

三、方案

借助 SetatefulSet 和 Headless Service,集群的部署方案设计如下(图片来自参考文章):

配置步骤大概罗列如下:

  1. 配置共享文件系统NFS

  2. 创建PV和PVC

  3. 创建ConfigMap

  4. 创建Headless Service

  5. 创建StatefulSet

  6. 初始化redis集群

四、实际操作

为了简化复杂度,这次先不配置 PV 和 PVC,直接通过普通 Volume 的方式来挂载数据。Kubernetes学习总结(15)—— Kubernetes 实战之部署 Mysql 集群

1、创建 ConfigMap

先创建redis.conf配置文件

appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

然后 kubectl create configmap redis-conf --from-file=redis.conf 来创建 ConfigMap。

2、创建 HeadlessService

apiVersion: v1
kind: Service
metadata:name: redis-servicelabels:app: redis
spec:ports:- name: redis-portport: 6379clusterIP: Noneselector:app: redisappCluster: redis-cluster

3、创建 StatefulSet

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:name: redis-app
spec:serviceName: "redis-service"replicas: 6template:metadata:labels:app: redisappCluster: redis-clusterspec:terminationGracePeriodSeconds: 20affinity:podAntiAffinity:preferredDuringSchedulingIgnoredDuringExecution:- weight: 100podAffinityTerm:labelSelector:matchExpressions:- key: appoperator: Invalues:- redistopologyKey: kubernetes.io/hostnamecontainers:- name: redisimage: "registry.cn-qingdao.aliyuncs.com/gold-faas/gold-redis:1.0"command:- "redis-server"args:- "/etc/redis/redis.conf"- "--protected-mode"- "no"resources:requests:cpu: "100m"memory: "100Mi"ports:- name: rediscontainerPort: 6379protocol: "TCP"- name: clustercontainerPort: 16379protocol: "TCP"volumeMounts:- name: "redis-conf"mountPath: "/etc/redis"- name: "redis-data"mountPath: "/var/lib/redis"volumes:- name: "redis-conf"configMap:name: "redis-conf"items:- key: "redis.conf"path: "redis.conf"- name: "redis-data"emptyDir: {}

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,用来作为管理节点:

kubectl run -i --tty redis-cluster-manager --image=ubuntu --restart=Never /bin/bash

进入 pod 内部先安装一些工具,包括 wget,dnsutils,然后下载和安装 redis:

wget http://download.redis.io/releases/redis-5.0.3.tar.gz
tar -xvzf redis-5.0.3.tar.gz
cd redis-5.0.3.tar.gz && make

编译完毕后 redis-cli 会被放置在 src 目录下,把它放进 /usr/local/bin 中方便后续操作。接下来要获取已经创建好的 6 个节点的 host ip,可以通过 nslookup 结合 StatefulSet 的域名规则来查找,举个例子,要查找 redis-app-0 这个 pod 的 ip,运行如下命令:

root@redis-cluster-manager:/# nslookup redis-app-0.redis-service
Server:     10.96.0.10
Address:    10.96.0.10#53Name:  redis-app-0.redis-service.gold.svc.cluster.local
Address: 172.17.0.10

172.17.0.10 就是对应的 ip。这次部署我们使用 0,1,2 作为 Master 节点;3,4,5 作为 Slave 节点,先运行下面的命令来初始化集群的 Master 节点:

redis-cli --cluster create 172.17.0.10:6379 172.17.0.11:6379 172.17.0.12:6379

然后给他们分别附加对应的 Slave 节点,这里的 cluster-master-id 在上一步创建的时候会给出:

redis-cli --cluster add-node 172.17.0.13:6379 172.17.0.10:6379 --cluster-slave --cluster-master-id adf443a4d33c4db2c0d4669d61915ae6faa96b46redis-cli --cluster add-node 172.17.0.14:6379 172.17.0.11:6379 --cluster-slave --cluster-master-id 6e5adcb56a871a3d78343a38fcdec67be7ae98f8redis-cli --cluster add-node 172.17.0.16:6379 172.17.0.12:6379 --cluster-slave --cluster-master-id c061e37c5052c22f056fff2a014a9f63c3f47ca0

集群初始化后,随意进入一个节点检查一下集群信息:

至此,集群初始化完毕,我们进入一个节点来试试,注意在集群模式下 redis-cli 必须加上 -c 参数才能够访问其他节点上的数据:

5、创建 Service

现在进入 redis 集群中的任意一个节点都可以直接进行操作了,但是为了能够对集群其他的服务提供访问,还需要建立一个 service 来实现服务发现和负载均衡(注意这里的 service 和我们之前创建的 headless service 不是一个东西)

yaml 文件如下:

apiVersion: v1
kind: Service
metadata:name: gold-redislabels:app: redis
spec:ports:- name: redis-portprotocol: "TCP"port: 6379targetPort: 6379selector:app: redisappCluster: redis-cluster

部署完做个测试:

Kubernetes学习总结(16)—— Kubernetes 实战之部署 Redis 集群相关推荐

  1. 在K8s上部署Redis 集群

    一.前言 架构原理:每个Master都可以拥有多个Slave.当Master下线后,Redis集群会从多个Slave中选举出一个新的Master作为替代,而旧Master重新上线后变成新Master的 ...

  2. k8s部署redis集群

    K8S部署Redis Cluster集群 kubernetes部署单节点redis: https://www.cnblogs.com/zisefeizhu/p/14282299.html Redis ...

  3. 通过operator部署redis集群(ucloud版)

    operator部署有状态的应用会简单很多 github文档:https://github.com/ucloud/redis-cluster-operator#deploy-redis-cluster ...

  4. Centos6.6部署Redis集群

    Centos6.6部署Redis集群 1 环境准备 1 环境安装redis 1 安装ruby 2 配置redis主从环境 3 部署redis sentinel服务器 5 集群使用 13 当前集群环境说 ...

  5. 三台机器使用Docker部署Redis集群

    三台机器使用Docker部署Redis集群 我们这里采用Docker在三台服务器上面进行Redis集群的搭建,它方便快捷.容易上手. 1.集群原理 在Redis集群中,所以的节点彼此关联,节点内部通过 ...

  6. operator部署redis集群

    operator部署redis集群 1.现在operator的redis相关包 git clone https://github.com/ucloud/redis-cluster-operator.g ...

  7. docker部署redis集群_Docker部署Redis集群----第九节(docker-redis哨兵集群“轮询分流”篇实例一)...

    到此,我们的 Redis 哨兵集群就结束了,本篇章是第九篇章,也是使用集群方式的实例一来实现php的轮询分流. 1.准备工作: 在我们上一篇章实现redis 哨兵集群的基础上开始,在服务器上部署php ...

  8. 2万字好文!手把手教你实现 Docker 部署 Redis 集群

    点击上方 "程序员小乐"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 关注订阅号「程序员小乐」,收看更多精彩内容 每日英文 Life is not ...

  9. docker部署redis集群实现动态扩缩容

    目录 思考 分布式存储的解决方案 哈希取余分区 一致性哈希算法分区 哈希槽分区 采用哈希槽分区 部署三主三从(docker) 准备工作 创建3主3从redis实例 进入容器中,构建主从关系 主从容错切 ...

最新文章

  1. Python+OpenCV 图像处理系列(5)—— 图像 ROI 操作及通道的拆分合并
  2. LeetCode Integer to Roman(数字转罗马)
  3. Stanford UFLDL教程 白化
  4. typedef enum的用法(枚举)
  5. Angular路由跳转时,如何传递信息
  6. 我的世界1.11服务器咋发信息,我的世界进服务器怎么注册怎么发信息
  7. kotlin编译失败_Kotlin使用GraalVM开发原生命令行应用
  8. 宁夏小学三年级计算机下册教案,宁夏信息技术教案
  9. 【转】8 个效果惊人的 WebGL/JavaScript 演示
  10. 《跟菜鸟学Cisco UC部署实战》-上线了(线下培训班开班,见百度云)
  11. 如何使用PowerShell将VS Code扩展导出到另一台计算机
  12. java布尔三目运算符_Java关系运算符,boolean运算符,三元运算符
  13. FCKeditor使用
  14. 联想电脑重装win7系统详细图文教程
  15. MATLAB实现 ICA 鸡尾酒会语音分离
  16. https 单向认证和双向认证
  17. !-- --与%-- --%
  18. 怎样安装linux系统
  19. 《大家的日语3》语法整理1~48课
  20. 压力表负值表示什么_弹簧管式压力表轻敲变动量居然有负值,我不知道是不是我学的不好,还是计量所所长脑子有病...

热门文章

  1. 中小学计算机听课记录表,小学数学听课记录范文表格
  2. matlab 分数 函数,Matlab 中 residuez函数的使用
  3. java中路由的使用方法_java – 在camel路由中使用方法作为生产者
  4. java年月日时分秒格式_Java 日期时间 LocalDate LocalTime LocalDateTime类
  5. 真空压力变送器怎么样零点标定_对于变送器你知道多少?
  6. 哪个不是python合法的标识符_哪个不是python合法标识符
  7. 智能计米器jk76怎么安装_春节智能锁消费指南:只看价格的后果有多严重?
  8. ros_readbagfile:未找到命令的解决方法
  9. C++新特性探究(七):初始化列表(Initialization List)
  10. 计算机配置cpo,使用域组策略及脚本统一配置防火墙-20210421070355.docx-原创力文档...