kubernetes环境部署运行codis

left2right · · 1869 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

初衷

为什么要在kubernetes上搭建codis系统,一个原因是很多服务已经运行在kubernetes上,将codis迁移到kubernetes上,可以更方便的使用;另一个重要原因是,结合kubernetes的特性,搭建一套基本不需要人为运维参与的codis系统(如果熟悉codis的话,会知道codis需要人的参与有些重,异常情况基本都需要人为参与处理),后面会详细说明如果做到基本不需要人为参与,原理、实现及一些折中选择。

目标

在kubernetes环境,一键部署一套codis系统,该codis系统能够稳定运行,并在一些意外情况,甚至极端下(如物理机当机等),能够自己进行修复,并恢复正常运行状态(部署完成后,基本不再需要人为参与)。一键对codis进行扩容(包括proxy和后端server)。经过大量测试,并在生产环境运行验证,当前这些目标基本满足。

github

https://github.com/left2right/codis (基于codis 3.2)

依赖

kubernetes环境

在kubernetes上部署一套codis系统,需要基本的kubernetes环境和docker环境,具体部署方法见相应文档。
如果想快速部署一套自己测试或者研究的单机kubernets环境,可以按照下面两个步骤来(mac):

  1. 部署docker
    https://docs.docker.com/toolbox/toolbox_install_mac/
  2. 部署minikube
    https://github.com/kubernetes/minikube (brew cask install minikube)
    kubernetes启动及验证(minikube)
    ###启动
    $ minikube start
    ###验证
    $ minikube status
    minikubeVM: Running
    localkube: Running

image依赖

  1. zookeeper image:
    gcr.io/google_samples/k8szk:v1
  2. golang image:
    golang:1.7.5
    这两个image均需要翻墙才能获取,可以找个国内的代理获取。
    image 获取成功检查
    ### 检查zookeeper image
    $ docker images |grep k8szk
    gcr.io/google_samples/k8szk  v1  ... ...
    ### 检查 golang image
    $ docker images |grep golang
    golang  1.7.5  ... ...

构建步骤

在kubernetes平台安装启动成功,而且拉取到上面依赖的两个image后,就可以构建codis系统了,具体如下:

###获取codis源码
$ git clone https://github.com/left2right/codis -b release3.2-k8s
### 构建codis docker镜像
$ cd codis
$ docker build -f Dockerfile  -t codis-image .

### 构建kubernetes环境的codis集群
$ cd  kubernetes
$ sh start.sh buildup
... ... plz wait
PONG 
#当你看到这个PONG的时候说明这套codis集群已经构建成功了,
#如果你没有等到PONG,那就需要检查下具体的报错内容了,祝顺利~

构成组件

文件说明

在codis/kubernetes/目录里面有以下这些文件:

  1. README.md 使用说明,包括创建codis集群,销毁集群,扩容等,具体如下:
    ### Build one codis cluster (codis master server has one slave)
    $ sh start.sh buildup
    ### Clean up the codis cluster
    $ sh start.sh cleanup
    ### Scale codis cluster proxy
    $ sh start.sh scale-proxy $(number)
    ### Scale codis cluster server
    $ sh start.sh scale-server $(number)
  2. start.sh 真个codis集群操作脚本,具体功能如上面README.md说明,挺简单的一个脚本,如果你想做些什么改动或者测试,可以在这个基础上做些尝试~
  3. codis-service.yaml codis在kubernetes环境中所有service的yaml文件,里面包括codis-dashboard, codis-proxy, codis-server, codis-fe, codis-ha
  4. codis-dashboard.yaml codis dashboard在kuberenetes环境的yaml文件
  5. codis-proxy.yaml codis proxy在kuberenetes环境的yaml文件
  6. codis-server.yaml codis server 在kuberenetes环境的yaml文件
  7. codis-ha.yaml codis-ha 在kuberenetes环境的yaml文件
  8. codis-fe.yaml codis-fe 在kuberenetes环境的yaml文件
  9. zookeeper/zookeeper-service.yaml zookeeper service 在kubernetes环境yaml文件
  10. zookeeper/zookeeper-service.yaml zookeeper 在kubernetes环境yaml文件

组件介绍

通过上面文件介绍,可以看到主要有zookeeper(可以用etcd等替代),codis-dashboard, codis-proxy, codis-server, codis-ha, codis-fe这几个组件组成,每个组件有一个相应的service,及一个具体的pod组织实现。

  1. zookeeper
    zookeeper是参考kubernetes官网https://kubernetes.io/docs/tutorials/stateful-application/zookeeper/ ,只是为了操作方便将相应的yaml文件的volume mounts注释掉了(生产环境使用中应该将zookeeper的持久化数据通过volume mounts 挂载出来),具体使用及相关说明见官网介绍

  2. codis-dashboard
    codis-dashboard即codis dashboard,其在codis中起的作用见GitHub介绍,dashboard使用StatefulSet来组织pod,并且replicas设置为1,整个集群只允许有一个。如果codis-dashboard异常,由kubernetes将其关闭,并重新启动起来,并加入到集群中。
    dashboard启动成功后,会通过kubernetes的postStart hook,发送一条命令检查zookeeper是否连接正常,以方便快速定位问题原因。在dashboard关闭时通过preStop hook,来确保dashboard正常关闭(将zookeeper上的锁删掉)。
    当一些极端情况(如物理机当机)导致dashboard非正常关闭,zookeeper上的锁没有删除掉(这会导致dashboard下次启动不起来),为了能让集群快速恢复正常状态,我们为codis-dashboard启动时添加了一个清除锁的开关(--remove-lock),如果打开开关,每次注册dashboard锁前,会先做一次清除锁的操作。

  3. codis-proxy
    codis-proxy即codis proxy,由于proxy是无状态的,使用ReplicationController来组织pod,这样可以快速的扩容缩容。通过replicas设置数量,默认是2个。
    codis proxy关闭前会发送一条命令将自己从集群中摘除出去。如果是一些异常情况,我们下面会介绍,由codis-ha将proxy从集群中摘除出去。然后由kubernetes重启一个proxy加入集群。

  4. codis-server
    codis-server即codis后端redis server,由于redis server要分属不同的group,为方便管理以及方便在没有人参与情况下恢复正常,使用StatefulSet来组织pod,replicas的数量即是整个集群中所有codis-server的数量,codis-server.yaml中有个配置的环境变量SERVER_REPLICA,这个设置的是每个group中codis-server的数量,默认是2个(一主一从)。
    为了使codis的server,尤其是一个group的server不部署在一个物理节点上,我们使用了kubernetes pod的反亲和性(podAntiAffinity),为了在物理节点有限时能够顺利部署codis集群,我们使用preferredDuringSchedulingIgnoredDuringExecution。如果想让所有codis server绝对不在一个node上,可以设置为requiredDuringSchedulingIgnoredDuringExecution,这样会提高系统的高可用性,但如果node节点不足会导致部署codis集群失败或者扩容codis server失败。

    在codis-server启动时,通过postStart hook,尝试为该server创建group,并将该server加入到group中,并尝试和group的master建立主从关系。在codis server关闭时尝试将该server从group中删除出去。该codis-server从属于哪个group,是由StatefulSet为该server分配的id,以及配置的环境变量SERVER_REPLICA,计算获得 gid=$(expr $sid / ${SERVER_REPLICA} + 1) 。这个过程中一些操作会失败,如创建已经存在的group等。一些操作失败并没有什么影响,直接跳过,一些失败会导致系统状态不正常,由后面的codis-ha将状态恢复为正常的状态,具体见后面说明。

    为提高系统的高可用性,可以将save的rdb文件挂载到外面,在启动时加载,挂载的目录是/codis,具体挂载方式和zookeeper类似,但考虑到性能,默认没有将rdb文件挂载出来,如果为了更高的可用性,可以参考zookeeper.yaml文件挂载出来。

  5. codis-ha

    当前codis 官方维护server ha使用的工具是redis-sentinel,并将之前的codis-ha去掉,这样选择的原因是codis-ha是一个单点,如果它状态不正常了,那集群的高可用就难以保证了,尤其是如果codis-ha需要人为参与的情况下,恢复正常着实会花费不少时间,redis-sentinel是集群的模式,不会因为某个节点的不正常,导致不能正常工作。但我们最终选择了codis-ha(在原有codis-ha的基础上进行修改),是因为sentinel能实现的功能太有限,只是在master状态异常时,重新选举一个master,但如果slave状态异常,以及重新建立主从关系,将group内各个server状态恢复正常,以及将proxy状态恢复正常,sentinel显然还无法做到。我们知道在kubernetes环境如果一个pod状态不正常了,会快速的关闭并重新启动起来,在这种场景下,codis-ha前面对比sentinel的不足,一定程度上缩减了不少,实际使用中效果确实可以。

    codis-ha的策略就是,通过dashboard,检查proxy和server的状态,如果proxy状态异常就关闭proxy,由kubernetes重启proxy,并加入集群;如果server状态异常,分几种情况:1. 是master,且有slave,则选择一个合适的slave(根据和master断开连接时间),提升为master;2.是master,没有slave,则直接关闭重启;3.是slave,则关闭,然后重启,加入集群。

    由于codis-ha严重依赖codis-dashboard,我们使用pod亲和性,将codis-ha和codis-dashboard部署在同一个节点。

  6. codis-fe

    codis-fe即codis-fe,codis的网页图形操作界面。PS在kubernetes环境主要用来观察下集群状态,qps等。

源码改动

kubernetes环境下的codis对源码做了如下修改:

  1. 增加kubernetes目录,里面存放相应的kubernets yaml文件及脚本
  2. 修改codis-ha,维护集群(server和proxy)状态,使codis proxy和server快速恢复为正常状态。
  3. 修改codis-dashboard,增加命令行传递product_name, product_auth,以满足创建不同product的codis,增加remove-lock开关,以使异常情况下,快速恢复dashboard
  4. 修改codis-proxy,增加命令行传递product_name, product_auth,以满足创建不同product的codis

注意点

注意事项

  1. 尽量确保codis-server的replicas能够整除SERVER_REPLICA,通过yaml文件可以看到SERVER_REPLICA为1,和其他在加入group时是对错误处理是不一样的,思考下你就明白,这是为了避免一个死锁。无论SERVER_REPLICA设置为任何正整数均可以,只是请确保集群中的group不会出现有的group有slave,有的只有master,整除即可~
  2. 留意你的数据量和机器实际可用内存~
  3. 建议先将该codis作为缓存使用一段时间,直到你熟悉了相关内容,及对其稳定性(也许和你的实际环境有很大关系)有了更深入的了解,再考虑将其作为一些数据的DB

问题定位

  1. codis-ha的log会实时的反应整个集群的状态,包括proxy,server,以及ha和dashboard,因为如果ha有问题log就看不了了,dashboard有问题,ha也就挂掉了。。。查看方法

    $ kubectl exec -it codis-ha-0 bash
    $ tail -f log/codis-ha-0.....
  2. 通过dashboard log更进一步定位问题的原因,方法类似

    $ kubectl exec -it codis-dashboard-0 bash
    $ tail -f log/codis-dashboard-0.....
  3. 如果你按照上面操作,尤其是你成功运行codis后,测试发现的任何问题,欢迎和我交流(yqzhang@easemob.com)~

其他

还有些事情及思考没有写完,改天再补充~


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:left2right

查看原文:kubernetes环境部署运行codis

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1869 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传