前言:有个需求是要持久化存储rabbitmq的消息数据,这样可以避免因为异常导致消息丢失的问题,找了好久都没有一个靠谱的答案,更恐怖的是一大堆人乱写一通,以下是本人解决问题的心路历程
0X00 问题&错误的尝试
rabbitmq数据持久化问题挺麻烦的,麻烦在rabbitmq的数据目录下的文件和文件夹的名字会依赖于本机的主机名,所以pod一旦重启或者移动到其他node,都会导致主机名变化,那么volume的挂载路径也得随之而变,哪能不停的监听pod状态去改yml文件呢?所以必须得解决主机名会发生变化的问题,首先想到的是看看rabbitmq的官方文档,看看能不能通过什么方式固定数据目录的名称,让他不随着主机名变化。
ReplicationController.yaml
apiVersion: v1
kind: ReplicationController
metadata:
labels:
component: rabbitmq
name: rabbitmq-controller
spec:
replicas: 1
template:
metadata:
labels:
app: taskQueue
component: rabbitmq
spec:
volumes: # 设置一个volumes,使用本机的/home/rabbitmq_data/目录进行数据存储
- name: rabbitmq-data
hostPath:
path: /home/rabbitmq_data
containers:
- image: rabbitmq:latest
name: rabbitmq
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5672
resources:
limits:
cpu: 1000m
env: # 设置环境变量,指定本rabbitmq节点的数据存储目录
- name: RABBITMQ_MNESIA_DIR
value: /var/lib/rabbitmq/mnesia/rabbitmq-server
volumeMounts: # 将上面声明的volumes挂载到容器内部
- mountPath: /var/lib/rabbitmq/mnesia/rabbitmq-server
name: rabbitmq-data
官方环境变量列表(https://www.rabbitmq.com/relocate.html):
不得不说,这个环境变量真的是坑爹的很,确实将数据存储目录改变成了固定值,但是你会发现持久化数据仍然会存在问题,因为在/var/lib/rabbitmq/mnesia/目录下还有一些鬼目录依赖hostname,目录名称会携带hostname,那么重启pod之后,hostname就改变了,所以数据无法持久化!!!!
举个例子,现在的pod hostname为rabbitmq-controller-tx75c,那么那些鬼目录可能就是rabbit@rabbitmq-controller-tx75c。pod重建后,hostname变成了rabbitmq-controller-4lc5h,那么rabbitmq在识别目录时就会存在问题,无法正常启动
0X01 解决方案
既然这个rabbitmq创建的鬼目录依赖hostname,那我们固定pod的hostname不就行了!?google了一番,很多人寄希望于这种解决方案,那么在部署的yml文件中指定hostname:
apiVersion: v1
kind: ReplicationController
metadata:
labels:
component: rabbitmq
name: rabbitmq-controller
spec:
replicas: 1
template:
metadata:
labels:
app: taskQueue
component: rabbitmq
spec:
nodeName: node1 # 指定pod的调度节点
hostname: rabbitmq-server # 固定pod的hostname
volumes: # 设置一个volumes,使用本机的/home/rabbitmq_data/目录进行数据存储
- name: rabbitmq-data
hostPath:
path: /home/rabbitmq_data
containers:
- image: rabbitmq:latest
name: rabbitmq
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5672
resources:
limits:
cpu: 1000m
volumeMounts: # 将上面声明的volumes挂载到容器内部
- mountPath: /var/lib/rabbitmq/mnesia/rabbit@rabbitmq-server
name: rabbitmq-data
看起来没啥问题了,结果将node的本地目录挂载到pod之后又有问题,提示没有权限,我寻思本地数据目录的权限我给的是666啊,应该没问题。后来想到rabbitmq会在目录中创建子目录,所以需要执行权限,那么数据目录权限直接777,搞定!
0X02 其他的一些鬼问题
1.0X01为运行一个rabbitmq pod,那么运行多个rabbitmq pod的话,数据存储该怎么搞?
如果k8s用的是ceph存储,那么应该不用考虑这些,不同的pod挂载不同的PV&PVC就完事。但是小集群可能没有ceph,这玩意bug多又难得维护。那么可以考虑将rabbitmq分散到每个node中,每个node上部署一个rabbitmq的pod,这个好办,使用Daemonset就行了,保证每个node节点会运行一个pod,然后每个pod挂载的又都是本机的hostpath,互不干扰,完美!