目前,有不少种基于Kubernetes搭建RabbitMQ集群的解决方案。今天笔者今天将要讨论咱们在Fuel CCP项目当中所采用的方式。这种方式加以转变也适用于搭建RabbitMQ集群的通常方法。因此若是你想要设计本身的解决方案,你应该收集一些更符合你定制化需求的文章。node
在Kubernetes内部运行RabbitMQ集群会遇到一系列有意思的问题。最早会遇到的问题是为了使各个节点之间互相可见,咱们应该如何命名各个节点。如下是一些符合规范的不一样的命名方法:git
在你尝试着启动第一个节点以前,你须要肯定容器之间能够经过选取名字的方式互通。例如,Ping命令能够访问@符号后面的节点名称。github
Erlang分布式方案(RabbitMQ所基于的实现方式)能够运行在两种命名方案当中的一种:短节点名或者长节点名。区别的关键点在于:名字中若是存在“.”,就属于长节点名;不然就是短节点名。在以上节点名举例当中,第一个就属于短节点名;第二个和第三个则属于长节点名。docker
综合以上要求,咱们能够有如下节点命名规则以供选择:json
以上的命名规则均须要采用长名字模式。可是DNS/节点名在K8S Pod内部配置的方式须要RabbitMQ 3.6.6之后版本才能够支持。因此若是你采用这种方式,请确认你的RabbitMQ的版本。安全
第二个成功的关键问题是RabbitMQ节点须要共享一个密钥Cookie。默认状况下RabbitMQ从一个文件当中读取这个Cookie(若是该文件不在,则自动生成一个)。为确保该Cookie在全部节点一致,咱们有如下方案:cookie
于RabbitMQ集群另一个必须知道是事情是当一个节点加入集群时,该节点的数据将会丢失,不管是什么样的数据。在常见的用例当中,这点可能可有可无。例如,当一个空节点加入到集群当中的时候,这时候该节点不存在任何数据丢失的问题。可是,当咱们有两个节点,他们已经相对独立的运行过一段时间以后,而且已经累积了一些数据时。这时候咱们没法在不损失任何数据的前提下将他们合并(注意:在网络中断或者节点宕机后回复一个集群都会有一样的问题,一样会有数据丢失)。对于特殊的数据,你可使用一些其余的解决方案。例如,把须要重置的节点中的数据先备份出来。可是,目前没有一个健壮的、自动的、全局的解决方案。网络
因此咱们的自动化集群解决方案受到咱们能容忍什么样的数据丢失这一方面的影响。app
假设你已经解决了全部命名规则相关的问题,而且用rabbitmqctl命令手工的创建了集群。如今是把咱们的RabbitMQ封装成自动化集群的时候了。就像咱们之前遇到的问题同样,没有一个解决方案能够解决全部的问题。dom
一个特定的解决方案只适合咱们并不关心服务中止或者连接丢失时数据丢失的问题。这种场景的一个例子就是当你使用RPC发送请求时,客户端能够在超时或者收到错误时重发请求。当服务恢复以后,RPC请求将再也不有效,相关数据也再也不有任何意义。幸运的是各个OpenStack组件之间的RPC调用正是这种状况。
在思考过以上全部问题以后,如今咱们能够搭建咱们本身的解决方案了。无状态是咱们的首选,因此咱们选择了IP地址而不是Pet集合。Autocluster插件将是咱们组织动态节点集群的首选。
查看过Autocluster的文档以后,咱们得出了如下配置项:
若是你尝试着按照以上搭建了几回集群,你会发现有时整个集群会分裂成几个互相没法联通的小集群。问题产生的缘由是启动时对于竞争问题的惟一保护措施在节点启动时会有随机的延迟现象。在最坏的状况下,每一个节点会认为它是第一个节点(例如这时在etcd中没有任何记录),因此这个节点就以无集群模式启动了。
Autocluster最终为该问题提出了一个很大的补丁。它在启动的过程当中增长了锁机制:节点在启动时最早申请启动锁资源,最后在该节点成功在后台注册以后才释放。目前只有etcd这个平台支持该功能。可是其它平台也能够很容易的支持该功能(在后台当中增长两个新的回调函数)。
另外一个问题是:K8S、Pet集合他们能够在启动的时候进行编排工做;在任什么时候间都只有一个节点处于启动状态。 该功能只处于初期测试阶段。提供该功能的补丁不只仅提供给K8S的用户,而是提供给全部平台的开发者。
目前惟一遗留的问题就是为咱们运行在非看管状态的集群增长一个监控系统。咱们须要监控rabbitmq的健康情况以及它是否和集群其它节点良好的工做在一块儿。
你也许还记得之前能够经过运行rabbitmqctl list_queues或者rabbitmqctl list_channels来监控。可是这种方案并不完美,由于它没法区别本地和远程的问题。同时它又明显的增长了网络负载。为了弥补这个缺陷,3.6.4版本以后推出了新的、轻量级的rabbitmqctl node_health_check。这是检查rabbitmq集群当中单节点健康情况最好的方法。
检查一个节点是否正确的加入集群须要作几方面的检查:
全部的这些能够经过独立的检查完成,检查可使用如下命令:
rabbitmqctl eval ‘autocluster:cluster_health_check_report().’
使用rabbitmqctl命令咱们能够检测出rabbitmq节点的任何问题,也能够经过该命令将该节点停掉。所以,K8S能够有机会施展魔法重启该节点。
若是你本身亲自按照这个方案搭建这个集群,你须要最新版本的RabbitMQ以及autocluster插件的定制化版本(目前启动锁机制这个补丁尚未合并到主版本当中)。
你能够查看Fuel CCP如何搭建集群,或者用你本身的实现方法使用独立的版原本搭建。
为了提示你该方案案如何实施,让咱们假设你已经复制了第二个repository,而且你已经有了一个叫作“demo”的K8S的命名空间。Etcd的服务已经在K8S集群中运行,而且能够经过”etcd”这个名字访问。你能够经过如下命令来搭建环境:
kubectl create namespace demo kubectl run etcd --image=microbox/etcd --port=4001 \ --namespace=demo -- --name etcd kubectl --namespace=demo expose deployment etcd
完成以上步骤后,用如下命令搭建RabbitMQ:
1. 用合适的RabbitMQ和Autocluster版本建立Docker镜像,并设置相应配置文件。
$ docker build . -t rabbitmq-autocluster
2. 保存Erlang的Cookie到K8S当中。
$ kubectl create secret generic --namespace=demo erlang.cookie \ --from-file=./erlang.cookie
3. 建立3节点RabbitMQ集群。为了简化操做,大家能够从如下连接下载rabbitmq.yaml文件https://github.com/binarin/rabbit-on-k8s-standalone/blob/master/rabbitmq.yaml.
$ kubectl create -f rabbitmq.yaml
4. 检查集群是否正常工做
$ FIRST_POD=$(kubectl get pods --namespace demo -l 'app=rabbitmq' \ -o jsonpath='{.items[0].metadata.name }') $ kubectl exec --namespace=demo $FIRST_POD rabbitmqctl \ cluster_status
你应该获得以下输出:
Cluster status of node 'rabbit@172.17.0.3' ... [{nodes,[{disc,['rabbit@172.17.0.3','rabbit@172.17.0.4', 'rabbit@172.17.0.7']}]}, {running_nodes,['rabbit@172.17.0.4','rabbit@172.17.0.7','rabbit@172.17.0.3']}, {cluster_name,<<"rabbit@rabbitmq-deployment-861116474-cmshz">>}, {partitions,[]}, {alarms,[{'rabbit@172.17.0.4',[]}, {'rabbit@172.17.0.7',[]}, {'rabbit@172.17.0.3',[]}]}]
这里最关键的一点是nodes与running nodes集合均有三个节点