为什么使用 StatefulSets?无状态 Pod 不能使用持久卷吗?

Why StatefulSets? Can't a stateless Pod use persistent volumes?

我正在努力理解 Stateful Sets。它们的使用与 "stateless" Pods 与 Persistent Volumes 的使用有何不同?也就是说,假设 "normal" Pod 可以声明持久存储,我缺少什么明显的东西需要这个新构造(有序 start/stop 等等)?

是的,常规 pod 可以使用持久卷。然而,有时您有多个 pods,逻辑上形成一个 "group"。这方面的例子是数据库副本、ZooKeeper 主机、Kafka 节点等。在所有这些情况下,都有一堆服务器,它们一起工作并相互通信。他们的特别之处在于,团队中的每个人都有自己的身份。例如,对于一个数据库集群,一个是主节点,两个是从节点,每个从节点都与主节点通信,让主节点知道自己有什么同步,什么没有同步。所以追随者知道 "db-x-0" 是主人,主人知道 "db-x-2" 是追随者并且拥有达到某个点的所有数据但仍然需要超出该点的数据。

在这种情况下,您需要一些无法从普通 pod 轻松获得的东西:

  1. 一个可预测的名字:你想开始你的 pods 告诉他们在哪里可以找到彼此,这样他们就可以形成一个集群,选举一个领导者等等,但是你需要提前知道他们的名字才能做那。普通 pod 名称是随机的,因此您无法提前知道它们。
  2. 稳定的 address/DNS 名称:您希望步骤 (1) 中可用的任何名称保持不变。如果一个正常的 pod 在另一台主机上重新启动(您重新部署,它所在的主机 运行 死机等),它将获得一个新名称和一个新 IP 地址。
  3. 组中的个人与其持久卷之间的持久 link:如果您的数据库主控之一 运行 所在的主机挂掉了它将移动到新主机,但应该连接到 相同的 持久卷,因为只有一个卷包含 "individual" 的正确数据。因此,例如,如果您重新部署由 3 个数据库主机组成的组,您希望同一个人(通过 DNS 名称和 IP 地址)获得相同的持久卷,因此主服务器仍然是主服务器并且仍然具有相同的数据,replica1 得到它是数据等

StatefulSets 解决了这些问题,因为它们提供(引用自 https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/):

  1. 稳定、唯一的网络标识符。
  2. 稳定、持久的存储。
  3. 有序、优雅的部署和缩放。
  4. 有序、优雅的删除和终止。

我并没有真正谈论 (3) 和 (4) 但这也可以帮助集群,因为你可以告诉第一个部署成为主控,下一个找到第一个并将其视为硕士等

正如一些人指出的那样,您确实可以通过使用常规 pods 和服务获得 一些 相同的好处,但它的工作量要大得多。例如,如果您想要 3 个数据库实例,您可以手动创建 3 个部署和 3 个服务。请注意,您必须手动创建 3 个部署 ,因为您不能将服务点指向部署中的单个 pod。然后,要向上扩展,您需要手动创建另一个部署和另一个服务。这确实有效,并且在 PetSet/PersistentSet 出现之前是一种常见的做法。请注意,它缺少上面列出的一些好处(例如持久卷映射和固定启动顺序)。

1: Why StatefulSets?

无状态应用程序: 通常,前端组件的扩展要求与后端完全不同,因此我们倾向于单独扩展它们。更不用说与(无状态)前端 Web 服务器相比,数据库等后端通常更难扩展。是的,术语“无状态”意味着在创建新容器时,既不存储过去的数据也不存储状态,也不需要持久化

有状态应用程序:有状态应用程序通常涉及某些数据库,例如 Cassandra、MongoDB 或 MySQL 并处理读取 and/or写信给它。

2: Can't a stateless Pod use persistent volumes?

基本上,有几种方法可以做到这一点。然而,它也有它自己的缺点。

1:每个 POD 实例使用一个副本集

  • 您可以创建多个 ReplicaSet——每个 pod 一个,每个 pod ReplicaSet 的期望副本数设置为 1,并且每个 ReplicaSet 的 引用专用 PersistentVolumeClaim 的 pod 模板。

  • 虽然这会在以下情况下自动重新安排 node故障或者pod意外删除,就麻烦多了 与拥有单个 ReplicaSet 相比。

  • 例如,想想在这种情况下您将如何缩放 pods。你 无法更改您必须创建的所需副本数 额外的 ReplicaSets 代替。使用多个 ReplicaSets 是 因此不是最好的解决方案。

2:在同一卷中使用多个目录

  • 您可以使用的一个技巧是让所有 pods 使用相同的 PersistentVolume,但是每个 pod 在该卷内有一个单独的文件目录,因为您不能以不同于单个 pod 的方式配置 pod 副本模板,你不能告诉每个实例它应该使用什么目录,但你可以使每个实例自动select(并且可能还创建)一个数据目录,该目录当时没有被任何其他实例使用。

  • 这个解决方案确实需要实例之间的协调,并且不容易正确执行。这也使共享存储量成为瓶颈。

这就是为什么人们应该鼓励使用有状态集