我们最近将数百个ZooKeeper实例从单独的服务器实例迁移到了Kubernetes,而期间没有停机。我们使用了强大的Kubernetes功能(例如端点)来简化流程,本文主要把迁移心得分享给大家,方便有同样需求的小伙伴们参考。有关一些重要的前提条件,比如网络,请参见最后。

zk01.jpg

传统ZooKeeper迁移

ZooKeeper是许多分布式系统的基础,这些分布式系统主要依靠ZooKeeper来组成集群,从而发挥分布式系统的威力。在幕后,它依靠一致性方法来组成集群:每个服务器实例都有一个配置文件,其中列出了所有成员主机名和数字ID,并且所有服务器都具有相同的服务器列表,如下所示:

server.1=host1:2888:3888

server.2=host2:2888:3888

server.3=host3:2888:3888

每个服务器都有一个名为myid的唯一文件,以告诉它与该列表对应的数字id。

只要不违反关键规则,就可以添加和删除主机:每台服务器必须能够达到其配置文件中列出的服务器的法定人数(定义为简单多数)。传统方式将ZooKeeper服务器迁移到新实例的涉及到较多方面:

  • 在服务器列表中使用“server.4 = host:4…”配置并启动新主机
  • 更新现有主机上的配置文件以添加新服务器条目,并从其服务器列表中删除已淘汰的主机
  • 滚动重启旧主机(3.4x分支中没有动态服务器配置)
  • 更新客户端中的连接字符串(如果客户端在错误时重新解析DNS,则可能只是更改CNAME记录)

这种方法的缺点是许多配置文件更改和滚动重新启动,您可能没有可靠的自动化解决方案。当我们开始将ZooKeeper迁移到Kubernetes时,我们开始考虑这种方法,但想出了一种更简单的方法。因为根据我们的经验,每次新领导人选举都有很小的风险,即花费足够长的时间来压倒依赖他们的系统。

新方法

我们的方法是将现有的ZooKeeper服务器部署在Kubernetes服务中,然后使用相同的ZooKeeper ID进行一对一的服务器到Pod替换,这只需要一次滚动重启就可以重新配置现有的ZK实例,然后逐个关闭服务器。我们不会在这里讨论为ZooKeeper配置Kubernetes拓扑的方法,也不会讨论简单的只读健康检查,这是很细节的,因为不同的方法可以实现同一个目的,只不过每种方法有优点和缺点。下面讨论的概念也是一样的。

我们将分五个步骤进行:

  • 完成前提条件,以确保我们的ZooKeeper集群已准备好迁移
  • 在部署ZooKeeper服务的Kubernetes中创建ClusterIP服务
  • 配置ZooKeeper客户端以连接到ClusterIP服务
  • 配置ZooKeeper服务器实例以通过ClusterIP服务地址执行对等事务
  • 用KubernetesPod中的ZooKeeper实例替换服务器上运行的每个ZooKeeper实例

对于下面的每个步骤,我们都将包含一个基础架构拓扑图,这些图将仅包含两个ZooKeeper实例,以便于理解,即使一个不想创建少于三个的集群也是如此。

完成先决条件

从一个可用的ZooKeeper集群开始,我们将要确保主机上的服务能够与我们的Kubernetes集群进行通信。在本文结尾处,我们提供了几种方法来实现这一点。

zk02.jpg

创建 ClusterIP 服务

为每个ZooKeeper服务器创建具有匹配的Endpoint资源的ClusterIP服务,它们应该暴露客户端端口(2181)和集群内部端口(2888,3888)。完成后,您应该能够通过以下方式连接到ZooKeeper集群。Kubernetes ClusterIP服务在这里很有用,因为它们为您提供了充当后端Pod的负载平衡器的静态IP地址,在这种情况下,我们将它们与服务到Pod的1:1映射一起使用,因此我们拥有静态每个Pod的IP地址。

zk02.jpg

重新配置ZooKeeper client

一旦能够通过Kubernetes ClusterIP服务连接到ZooKeeper群集,则是暂停并重新配置所有客户端的好时机。如果您在ZooKeeper连接字符串中使用CNAME记录,请更改DNS记录。最简单的方法是重新启动所有客户端。否则它们将在连接失败时重新解析DNS条目;如果您不使用CNAME记录,则需要使用新的连接字符串并重新启动所有客户端进程。在此时,新的连接字符串和旧的链接字符串仍然可以使用。

zk03.jpg

重新配置ZooKeeper实例

接下来,我们将使ZooKeeper服务器通过这些ClusterIP服务进行对等通信,为此,我们将修改配置文件以合并ClusterIP服务的地址。配置zk_quorum_listen_all_ips也很重要:没有它,ZK实例将无法尝试绑定到主机上任何接口上都不存在的ip地址,因为它是K8S服务IP。

server.1=zk1-kube-svc-0:2888:3888  
server.2=zk2-kube-svc-1:2888:3888  
server.3=zk3-kube-svc-2:2888:3888  
zk_quorum_listen_all_ips: true

滚动重启这些主机,现在我们准备开始用pod替换主机。

zk04.jpg

用Pod 替换 ZooKeeper 主机

一次替换一台服务器,我们将执行以下步骤:

  • 选择一个ZK服务器及其对应的ClusterIP服务
  • 关闭服务器上的ZK进程
  • 启动一个配置为与关闭的ZK服务器相同的服务器列表和myid文件的Pod
  • 等待Pod中的ZK启动并同步来自其他ZK节点的数据

就是这样,您的ZooKeeper集群现在已经在Kubernetes中运行,并且具有所有先前的数据。

zk06.jpg

网络先决条件

为了使这些步骤正常工作,需要处理一些网络设置。您需要采取步骤来确保以下各项:

  • 需要从所有需要连接到ZooKeeper的服务器上路由Kubernetes Pod IP地址
  • 所有连接到ZooKeeper的服务器都必须能够解析Kubernetes服务主机名
  • Kube-proxy必须在所有需要连接到ZooKeeper的服务器上运行,以便它们可以访问ClusterIp服务

iyacontrol
1.4k 声望2.7k 粉丝

专注kubernetes,devops,aiops,service mesh。