原文参考 https://spacelift.io/blog/statefulset-vs-deployment
有状态应用程序与无状态应用程序
StatefulSet 旨在运行应用的有状态组件,而 Deployments 用于无状态组件。
当系统不需要在自身内部存储任何数据时,系统是无状态的。例如,网站和 Web 应用程序前端通常是无状态的。另一方面,数据库等应用程序被称为有状态的。它们需要持久性存储,其寿命超过单个容器副本的生命周期。
Kubernetes 以管理无状态服务而闻名。当应用程序是无状态的时,其 Pod 是完全可互换的;缩放操作不会导致任何数据丢失。但是,对于有状态应用程序来说,情况并非如此。要在 Kubernetes 中运行有状态服务,您需要使用 StatefulSet 来确保稳定的 Pod 复制和数据持久性。
什么是 Kubernetes StatefulSet?
Kubernetes StatefulSet 是一个 API 对象,专门用于支持有状态应用程序组件。它根据您提供的规范创建一组配置相同的 Pod,但每个 Pod 都被分配了一个不可互换的身份。如果必须重新调度 Pod 或扩展 StatefulSet,则 Pod 将保留其标识。
持久 Pod 身份允许存储卷与 StatefulSet 中的特定 Pod 相关联。它们还有助于平稳地扩展操作和滚动更新,其中 Pod 以可预测的顺序添加和删除。
何时使用 StatefulSets?
让我们考虑一个在 Kubernetes 中运行 MySQL 数据库服务器的三个副本的简单示例。部署应配置一个 Pod 作为主要角色,处理读写操作,其余两个 Pod 作为 MySQL (约定的)只读副本。
连接到数据库的应用程序将始终需要连接到处于主要角色的 Pod 才能接收读写访问权限。如果使用 Deployment 或 ReplicaSet,则无法做到这一点,因为调度或复制更改将生成新的 Pod 标识。应用程序无法知道哪个 Pod 是主要的 MySQL 实例。
StatefulSets 消除了这个问题。StatefulSet 中的每个 Pod 都被分配了一个可预测且一致的网络身份,格式为 <statefulset-name>-<pod-ordinal-index>。MySQL 部署中的三个 Pod 将按如下方式命名:
- mysql-0 – 第一个 Pod,主要角色,可读写
- mysql-1 – (约定)只读副本
- mysql-2 – (约定)只读副本
读写程序连接到 mysql-0 与 MySQL 主实例交互;只读的程序访问其他只读副本。由于 StatefulSets 还保证有序更新,因此只有在缩减到零时,才会终止重要的 mysql-0 副本。将始终首先删除只读副本。
此外,StatefulSets 的持久存储特性意味着每个 Pod 将始终重新附加自己的存储卷,即使在重新调度后也是如此。
必须单独创建Headless Service使得Pods支持稳定的网络身份。它是一个没有 ClusterIP 的 Service,允许直接将请求发送到每个 Pod,而不需要通过负载均衡。每个 Pod 都有一个唯一的 DNS 记录,而不是所有 Pod 共用一个 DNS 记录。
什么是 Kubernetes Deployment?
Deployment 是一个 API 对象,用于管理属于无状态应用程序的 Pod 和 ReplicaSet。它们支持声明性配置、推出和回滚。您可以使用它们来自动更新 Pod。
由于部署使用声明性管理模型,因此只需定义所需状态的外观。当您应用部署清单时,Kubernetes 会自动将其描述的状态与集群中的当前版本进行比较。然后,部署控制器会将现有状态与新的所需状态进行协调,从而根据需要添加和删除 Pod。
实际上,它允许您通过调整 Deployment 清单中的值来更改 Pod 副本的数量。Kubernetes 将自动添加正确数量的新 Pod 或删除现有 Pod 以实现推出。部署还允许您在检测到问题并回滚到以前的状态时暂停推出。
何时使用 Deployment?
使用部署来运行需要从声明性更新和回滚中受益的无状态应用程序。它们允许您安全地推出更改,而不会受到停机的威胁。
部署会根据您定义的一致规范自动创建 Pod 和 ReplicaSet。这消除了配置、更改和扩展容器化应用程序的大部分管理负担。部署控制器处理编排任务,并将每个 Pod 分配给最合适的节点。
此外,使用 Deployment 可使应用程序对群集中发生的任何故障更具弹性。部署控制器将确保指定数量的 Pod 保持运行;它们将在节点故障后自动重新调度。
将 Pod 包装在部署中始终比在没有控制器管理的情况下“裸”运行它们更可取,因为这些 Pod 无法直接在集群的节点上扩展或复制。
