RabbitMQ 是一个用 Erlang 编写的消息代理,允许您组织一个跨多个节点进行完整数据复制的故障转移集群,其中每个节点都可以服务读写请求。 在生产运行中拥有许多 Kubernetes 集群,我们支持大量 RabbitMQ 安装,并且面临着在不停机的情况下将数据从一个集群迁移到另一个集群的需要。
我们至少在两种情况下需要此操作:
- 将数据从不在 Kubernetes 中的 RabbitMQ 集群传输到一个新的——已经“kubernetized”(即在 K8s pod 中运行)的集群。
- 将 Kubernetes 内的 RabbitMQ 从一个命名空间迁移到另一个命名空间(例如,如果电路由命名空间分隔,则将基础设施从一个电路转移到另一个电路)。
本文中提出的方法主要针对以下情况(但完全不限于此):存在旧的 RabbitMQ 集群(例如,3 个节点),该集群要么已位于 K8s 中,要么位于某些旧服务器上。 托管在 Kubernetes 上的应用程序(已经存在或将来)可以使用它:
...我们面临着将其迁移到 Kubernetes 中的新生产环境的任务。
首先,将描述迁移本身的一般方法,然后将描述其实现的技术细节。
迁移算法
任何操作之前的第一个初步阶段是检查旧 RabbitMQ 安装中是否启用了高可用性模式(ha-mode: all
:
下一步是在 Kubernetes Pod 中建立一个新的 RabbitMQ 集群(例如,在我们的例子中,由 3 个节点组成,但它们的数量可能不同)。
之后,我们合并新旧 RabbitMQ 集群,获得单个集群(6 个节点):
启动新旧RabbitMQ集群之间的数据同步过程。 一旦集群中所有节点之间的所有数据同步,我们就可以切换应用程序以使用新集群:
经过这些操作后,就足以从 RabbitMQ 集群中删除旧节点,移动可以认为完成了:
我们在生产中多次使用了这个方案。 然而,为了我们自己的方便,我们在一个专门的系统中实现了它,该系统在多个 Kubernetes 集群之间分发标准 RMQ 配置 (对于那些好奇的人:我们正在谈论
让我们在实践中尝试一下
需求
细节很简单:
- 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. 首先,我们将新的 RabbitMQ 部署在 其他 命名空间与 同样的 ErlangCookie
和用户的密码。 为此,我们将执行上述操作,将安装 RMQ 的最终命令更改为以下内容:
helm install . --name rmq-new --namespace rmq-new
2. 现在您需要将新集群与旧集群合并。 为此,请转到每个 Pod 新 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
找到其中一个节点的地址 老 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 更新到具有更改配置的新版本时,我们使用了相同的策略 - 一切都像时钟一样工作。
PS
作为本材料的逻辑延续,我们正在准备有关 MongoDB(从硬件服务器迁移到 Kubernetes)和 MySQL(我们如何在 Kubernetes 内准备此 DBMS)的文章。 它们将在未来几个月内发布。
聚苯硫醚
另请阅读我们的博客:
来源: habr.com