探索 StatefulSet

学习目标

  • 比较 Deployment 与 StatefulSet

什么是 Kubernetes 中的 StatefulSet?

您已经使用 Deployment 和 ReplicaSet 将应用程序部署到集群,但这些资源不适用于数据库等有状态应用程序。进一步了解有状态应用程序,并弄清如何在 Kubernetes 中部署它们。

在 Kubernetes 中,部署无状态应用程序很容易。您可以使用 Deployment,它会创建一个 ReplicaSet,后者又创建 Pod。如果一个 Pod 失败,ReplicaSet 会创建一个新的。这些 Pod 根据其规范和应用的标签来标识。然而,由 ReplicaSet 创建的 Pod 在名称末尾会被分配一个随机的哈希值,例如 hello-kyma-59fd556764-fkr6d。这是因为这些 Pod 是无状态的,可以被任何具有相同规范和标签的其他 Pod 替换。

相反,有状态应用程序通常需要唯一且一致的标识符,例如稳定的主机名。由于 ReplicaSet 的特性,这会变得棘手,因为它们会为 Pod 随机分配新名称,使得识别 Pod 并连接到它变得困难。为此,Kubernetes 提供了 StatefulSet。

根据 Kubernetes 官方文档,当您的工作负载需要以下一项或多项特性时,可以使用 StatefulSet:

  • 稳定、唯一的网络标识符

  • 稳定、持久的存储

  • 有序、优雅的部署和扩缩容

  • 有序的自动化滚动更新

因此,StatefulSet 管理一组具有唯一持久身份和稳定主机名的 Pod,Kubernetes 会在重新调度过程中保持这些标识。

StatefulSet 如何工作?

创建 StatefulSet 时,Pod 会按顺序依次创建。这意味着第一个 Pod 以名称 my-stateful-app-0 创建,第二个以名称 my-stateful-app-1 创建,依此类推。最大编号等于您在 StatefulSet 中指定的副本数。这种行为与 ReplicaSet 不同,在 ReplicaSet 中,Pod 是以随机顺序同时创建的。

StatefulSet 首先启动索引最小的 Pod,并等待它变为就绪。只有在这之后,它才会继续创建下一个 Pod,从而确保 Pod 按顺序创建,并且每个 Pod 在下一个启动之前都已就绪。此外,您可以将持久存储挂载到有状态 Pod 上,以防 Pod 被删除时数据丢失。这对于数据库等需要持久保存数据的应用程序特别有用。如果数据库 Pod 崩溃或被删除,数据仍保留在持久存储上。

查看一个 StatefulSet 的示例清单:

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-stateful-app
spec:
selector:
matchLabels:
app: my-stateful-app
serviceName: my-stateful-app
replicas: 3
template:
metadata:
labels:
app: my-stateful-app
spec:
containers:
- name: my-stateful-app
image: ghcr.io/sap-samples/kyma-runtime-learning-journey/hello-kyma:1.0.0
ports:
- containerPort: 8080
name: web

需要考虑的一个重要部分是,将 StatefulSet 的 Service 定义为所谓的无头 Service(headless Service)。当使用 Service 将流量负载均衡到由 ReplicaSet 管理的 Pod 时,Service 通过标签来标识 Pod,因为这些 Pod 的名称末尾会被分配一个随机哈希值。相反,对于 StatefulSet,Pod 通过其稳定的名称来标识,例如 my-stateful-app-1。在这种情况下,不需要一个带单个 IP 地址的负载均衡器作为 Service 来将流量负载均衡到随机命名的 Pod。

查看无头 Service 清单的示例:

apiVersion: v1
kind: Service
metadata:
name: my-stateful-app
spec:
clusterIP: None
selector:
app: my-stateful-app
ports:
- name: web
port: 80

注意

在 Kubernetes 中,如果 Service 的 clusterIP 设置为 None,则该 Service 被视为无头 Service。这意味着该 Service 没有集群 IP。

小结

在本课中,您了解到 StatefulSet 用于部署有状态应用程序,例如数据库或消息代理。您现在还能够区分 StatefulSet 与 ReplicaSet,因为前者按顺序创建具有唯一索引和稳定名称的 Pod。此外,您还了解到可以使用无头 Service 连接到 StatefulSet 的 Pod。

延伸阅读

Kubernetes 中的 StatefulSet