
RabbitMQ是用Erlang语言编写的消息代理,它使您可以组织故障转移群集,并将其完整数据复制到多个节点,每个节点可以在其中处理读写请求。 在生产中有许多Kubernetes集群的情况下,我们支持大量RabbitMQ安装,并且面临着在不停机的情况下将数据从一个集群迁移到另一个集群的需求。
在至少两种情况下,此操作对我们来说是必需的:
- 将数据从不在Kubernetes中的RabbitMQ集群传输到已经被“调优”(即在K8s pod中运行)的新集群。
- Kubernetes中RabbitMQ从一个名称空间迁移到另一个名称空间(例如,如果路径由名称空间分隔,则将基础结构从一个路径转移到另一路径)。
本文中提出的方法主要针对(但不限于这些)情况,其中存在一个旧的RabbitMQ集群(例如3个节点),位于K8或某些旧服务器上。 Kubernetes中托管的应用程序可以使用(已经存在或将来使用):

...并且我们面临着将其迁移到Kubernetes的新产品中的挑战。
首先,将描述迁移本身的一般方法,然后介绍其实现的技术细节。
迁移算法
执行任何操作之前的第一步,即第一步,是验证是否在旧的RabbitMQ安装中启用了高可用性(
HA )模式。 原因很明显-我们不想丢失任何数据。 要执行此检查,您可以转到RabbitMQ管理面板,并在管理→策略标签中,确保值
ha-mode: all
:

下一步是在Kubernetes窗格中创建一个新的RabbitMQ集群(例如,在我们的示例中,该集群由3个节点组成,但是它们的数量可能不同)。
之后,我们合并旧的和新的RabbitMQ集群,获得单个集群(6个节点):

启动了新旧RabbitMQ集群之间的数据同步过程。 在集群中所有节点之间同步所有数据之后,我们可以将应用程序切换为使用新集群:

完成这些操作后,从RabbitMQ集群中删除旧节点就足够了,并且可以认为移动已完成:

我们已经在生产中反复使用此方案。 但是,为了他们自己的方便,我们在一个专用系统的框架内实现了它,该系统在Kubernetes集群的集合上分发典型的RMQ配置
(对于那些好奇的人:我们正在谈论的是addon-operator ,我们最近在谈论 ) 。 下面提供了单独的说明,任何人都可以在其装置上应用这些说明,以尝试所建议的解决方案。
我们在实践中尝试
要求条件
细节非常简单:
- Kubernetes集群(minikube也适用);
- RabbitMQ集群(可以部署在裸机上,并根据官方Helm图表在Kubernetes中作为常规集群进行制作)。
对于下面描述的示例,我将RMQ部署到Kubernetes,并将其命名为
rmq-old
。
展位准备
1.下载Helm图表并对其进行一些编辑:
helm fetch --untar stable/rabbitmq-ha
为了方便起见,我们设置密码
ErlangCookie
并设置
ha-all
策略,以便默认情况下,队列在RMQ集群的所有节点之间同步:
rabbitmqPassword: guest rabbitmqErlangCookie: mae9joopaol7aiVu3eechei2waiGa2we definitions: policies: |- { "name": "ha-all", "pattern": ".*", "vhost": "/", "definition": { "ha-mode": "all", "ha-sync-mode": "automatic", "ha-sync-batch-size": 81920 } }
2.设置图表:
helm install . --name rmq-old --namespace rmq-old
3.转到RabbitMQ管理面板,创建一个新队列并添加一些消息。 将需要它们,以便在迁移后我们可以确保所有数据都已保存并且我们没有丢失任何数据:

测试平台已经准备就绪:我们拥有“旧的” RabbitMQ,其中包含需要传输的数据。
RabbitMQ集群迁移
1.首先,使用用户
的相同 ErlangCookie
和密码,将新RabbitMQ部署到
其他名称空间中。 为此,我们执行上述操作,将最终的RMQ安装命令更改为以下内容:
helm install . --name rmq-new --namespace rmq-new
2.现在,您需要将新群集与旧群集合并。 为此,请转到
新 RabbitMQ的每个吊舱并执行以下命令:
export OLD_RMQ=rabbit@rmq-old-rabbitmq-ha-0.rmq-old-rabbitmq-ha-discovery.rmq-old.svc.cluster.local && \ rabbitmqctl stop_app && \ rabbitmqctl join_cluster $OLD_RMQ && \ rabbitmqctl start_app
OLD_RMQ
变量
OLD_RMQ
旧 RMQ群集的节点之一
OLD_RMQ
地址。
这些命令将停止
新 RMQ群集的当前节点,将其附加到旧群集,然后重新启动它。
3. 6个节点的RMQ集群已准备就绪:

您必须等待,直到所有节点之间的消息同步为止。 不难猜测,消息的同步时间取决于部署集群的熨斗的容量以及消息的数量。 在所描述的场景中,它们只有10个,因此数据是立即同步的,但是由于有足够多的消息,同步可能要花费数小时。
因此,同步状态为:

在此,
+5
表示消息
已经在
另外 5个节点上(“
Node
字段中指定的内容除外)。 因此,同步成功。
4.仅需将应用程序中的RMQ地址切换到新群集(此处的具体操作取决于您所使用的技术堆栈和其他应用程序特定条件),然后您就可以告别旧的了。
对于最后一个操作(即,将应用程序切换到新集群后),我们转到
旧集群的每个节点并执行以下命令:
rabbitmqctl stop_app rabbitmqctl reset
群集“忘记”了旧节点:您可以删除旧的RMQ,这将完成迁移。
注意 :如果将RMQ与证书一起使用,则基本上没有变化-移动过程将完全相同。结论
当我们需要转移RabbitMQ或仅移至新集群时,所描述的方案几乎适用于所有情况。
在我们的案例中,当从许多地方访问RMQ时,困难仅发生一次,而我们没有机会在任何地方将RMQ地址更改为新地址。 然后,我们在具有相同标签的相同命名空间中启动了一个新的RMQ,以使其落入现有服务和Ingress的控制之下。当我们启动Pod时,我们用手操作了这些标签,并在开始时将其删除了,这样请求就不会落在一个空的RMQ上,并且消息同步后将其重新添加。
在将RabbitMQ更新为具有修改后配置的新版本时,我们使用了相同的策略-一切都像时钟一样工作。
聚苯乙烯
作为该材料的逻辑上的延续,我们正在准备有关MongoDB(从铁服务器迁移到Kubernetes)和MySQL(在Kubernetes中“准备”该DBMS的选项之一)的文章。 它们将在未来几个月内发布。
PPS
另请参阅我们的博客: