rabbitmq
RabbitMQ是实现了高级消息队列协议的开源消息代理软件。RabbitMQ服务器是用Erlang语言编写的,而聚类和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。同时rabbitmq的使用非常的广泛,所以使用容器化的方式快速部署rabbitmq集群非常的有必要。
关于rabbitmq服务组成
rabbitmq服务实质邮4大部分组成
- epmd服务,rabbitmq起来后会自动的启动epmd服务,empd服务是erlang的一个小程序,专门用来做端口管理的。通常端口是4369
- rabbitmq amqp server,这个服务就是我们通常使用rabbitmq服务的时候,链接的5672端口的服务,使用来支持amqp服务的。通常端口是5672
- rabbitmq cluster server,主要是用来做cluster节点之间的心跳发现的,通常端口是25672
- 如果开启来rabbitmq manager plugin,会有一个manager api服务,通常端口是15672
除以上的服务之外,还有一个是erlang自带的数据库,专门用来做分部署服务发现的: mnesia数据库。可以从官网查看详细的文档rabbitmq官网
容器化步骤
容器化的第一步是制作rabbitmq镜像,rabbitmq是基于erlang语言开发的,所以需要在erlang环境中运行,制作rabbitmq镜像,也非常的简单,需要参照官网对应rabbitmq版本和对应的erlang的版本进行镜像制作,由于rabbitmq自身有官方的镜像,所以在这片文章中我直接只用rabbitmq官方镜像。rabbitmq官方镜像有带manager-plugin的和不带plugin的。我们使用带manager-plugin的。除此之外,我们依靠官方的一个auto-cluster插件去完成rabbitmq的集群自动初始化。所以还需要在官方镜像的基础上安装auto-cluster插件。
FROM 3.7.26-management-alpine
ADD https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.10.0/autocluster-0.10.0.ez /opt/rabbitmq/plugins/
ADD https://github.com/rabbitmq/rabbitmq-autocluster/releases/download/0.10.0/rabbitmq_aws-0.10.0.ez /opt/rabbitmq/plugins/
RUN rabbitmq-plugins enable --offline rabbitmq_management && rabbitmq-plugins enable --offline autocluster
编译制作镜像完成后,开始写k8s相关的yaml文件,并部署rabbitmq集群
部署rabbitmq集群
auto-cluster插件也是erlang开发的,同时它需要去k8s中查询endpoint,所以需要有对应的查询k8s的endpoint的权限,第一步是创建RBAC。
创建RBAC
apiVersion: v1
kind: ServiceAccount
metadata:
name: rabbitmq-autocluster
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: rabbitmq-autocluster
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: rabbitmq-autocluster
namespace: default
创建headless service
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: rabbitmq
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 3.7.26
name: rabbitmq-demo
namespace: default
spec:
clusterIP: None
ports:
- name: amqp
port: 5672
protocol: TCP
targetPort: 5672
selector:
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 3.7.26
sessionAffinity: None
type: ClusterIP
创建secret保存adminuser,pass和erlang cookie
apiVersion: v1
kind: Secret
metadata:
labels:
app.kubernetes.io/name: rabbitmq
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 1.1.1
name: rabbitmq-config
namespace: default
data:
rabbitmqDefaultPass: base64 password
rabbitmqDefaultUser: base64 user
rabbitmqErlangCookie: base64 cookie
自行更改对应的user,pass,cookie
创建statefulset
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app.kubernetes.io/name: rabbitmq
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 3.7.26
name: rabbitmq-demo
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 3.7.26
serviceName: rabbitmq-demo
template:
metadata:
labels:
app.kubernetes.io/instance: rabbitmq-demo
app.kubernetes.io/version: 3.7.26
spec:
containers:
- env:
- name: RABBITMQ_DEFAULT_USER
valueFrom:
secretKeyRef:
key: rabbitmqDefaultUser
name: rabbitmq-config
- name: RABBITMQ_DEFAULT_PASS
valueFrom:
secretKeyRef:
key: rabbitmqDefaultPass
name: rabbitmq-config
- name: RABBITMQ_ERLANG_COOKIE
valueFrom:
secretKeyRef:
key: rabbitmqErlangCookie
name: rabbitmq-config
- name: MY_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: K8S_SERVICE_NAME
value: rabbitmq-oam-mq-mq-1
- name: RABBITMQ_USE_LONGNAME
value: "true"
- name: RABBITMQ_NODENAME
value: rabbit@$(MY_POD_NAME).$(K8S_SERVICE_NAME)
- name: RABBITMQ_NODE_TYPE
value: disc
- name: AUTOCLUSTER_TYPE
value: k8s
- name: AUTOCLUSTER_DELAY
value: "10"
- name: AUTOCLUSTER_CLEANUP
value: "true"
- name: CLEANUP_WARN_ONLY
value: "false"
- name: K8S_ADDRESS_TYPE
value: hostname
- name: K8S_HOSTNAME_SUFFIX
value: .$(K8S_SERVICE_NAME)
image: 制作的rabbitmq镜像
imagePullPolicy: IfNotPresent
name: rabbitmq
resources:
limits:
cpu: 512m
memory: 1G
requests:
cpu: 521m
memory: 1G
securityContext:
privileged: true
volumeMounts:
- mountPath: /var/lib/rabbitmq
name: data
serviceAccount: rabbitmq-autocluster
volumes:
- emptyDir: {}
name: data
关于auto-cluster插件依赖的环境变量的配置请参考rabbitmq-autocluster,有详细的介绍和说明,可以根据自己的实际情况进行设置。
需要注意的点
- AUTOCLUSTER_CLEANUP 这个环境变量是用来设置自动清除不健康的节点,需要配合CLEANUP_WARN_ONLY=false,同时也依赖CLEANUP_INTERVAL这个参数,默认是60s,每隔一分钟进行一次检测,当检测到不健康节点的时候,就会吧节点从集群中删除,对应的节点上的数据也相应丢失,如果对应的queue没设置成mirror queue是非常危险的。所以一般会AUTOCLUSTER_CLEANUP =false。如果AUTOCLUSTER_CLEANUP设置成true,当不健康节点节点从集群中剔除,后面故障节点又重新起来后,由于故障节点中存储的的信息中,包含该节点属于之前的集群,所以节点在起来后会尝试加入之前的集群,但是之前的集群已经吧它剔除, 所以导致故障节点一直起不来,并且报错: 大致意思是,节点yyy尝试加入集群xxx,但是集群xxx不认为节点yyy是xxx的节点。 这个时候,需要吧对应的故障节点的数据目录下的mnesia数据目录(mnesia数据目录是erlang自带的mnesia数据库的数据存储目录)。然后重启节点,让节点重新加入集群。