有状态应用在 Kubernetes 里对应的对象就是 StatefulSet。跟 Deployment 一样,StatefulSet 也是一种控制器,区别是一个控制无状态应用,一个控制有状态应用。当一个有状态的 Pod 挂掉之后(或者是所在节点出现故障),这个 Pod 实例必须在其它的节点上重建,但是新的实例必须和被替换的实例拥有相同的名称、网络标识和状态,StatefulSet 可以保证 Pod 在重新调度以后保留它们之前的标识和状态,这样就可以方便的扩缩容。
应用一旦牵扯到状态,控制起来就会比较麻烦,因此 StatefulSet 要比 Deployment 复杂许多。具体来说,StatefulSet 适合具有以下需求的场景:
* 稳定的持久化存储 Pod 在重新调度之后还能继续访问之前的存储数据
* 稳定的网络标志 Pod 在重新调度后其名字和主机名保持不变
* 有序部署:构成应用的多个 Pod 启动顺序是固定的,适合 Pod 之间有依赖关系的情况
* 有序删除:删除应用时 Pod 销毁顺序跟启动顺序正好相反
StatefulSet 中每个 Pod 具有固定的名字,Pod 的 DNS 域名格式为`statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local`。跟普通域名一样,子域在前,主域在后,只不过节数比较多而已。各部分含义如下:
* `statefulSetName`:StatefulSet 名字
* `0..N-1 Pod 的序号`:从 0 到 N-1
* `serviceName`:Headless Service(没有 ClusterIP 的 Service) 名字,StatefulSet 无法使用普通的 Service(有一个 ClusterIP 作为服务入口) 来提供应用服务(包括负载均衡)。这是因为 StatefulSet 里的各个 Pod 不是对等的,只能由用户自己来实现服务内部的网络路由
* `namespace`:服务所在的命名空间,Headless Service 和 StatefulSet 必须在相同的命名空间下
* `svc.cluster.local`:集群域名
StatefulSet 的设置由以下 3 部分组成:
* 用于定义网络标志的 Headless Service
* 用于创建 PV(持久存储卷)的 volumeClaimTemplates
* 定义具体应用的 StatefulSet
#### Headless Service(无头服务)
Headless Service 是指不为 Service 设置 ClusterIP(入口 IP 地址),只通过标签选择器将后端的 Pod 列表返回给调用的客户端,客户端自行决定如何处理这个 Pod 列表。
在前面讲解 Deployment 时,我们知道每个创建的 Pod 的名称都是没有顺序的,名称最后有一截 Hash 值,因此这样创建的 Pod 是无序的。但是 StatefulSet 中要求 Pod 名称必须有序,每个 Pod 名称具有唯一性,并且当 Pod 重建后名称依然要保持一致,Pod 的名称就是唯一性的标志,必须持久有效,因此会使用 Headless Service 服务。
#### volumeClaimTemplates(卷申请模板)
有状态自然是需要持久化的,所以 StatefulSet 引入了 PV(持久存储卷) 和 PVC(持久存储卷声明) 对象来持久存储服务产生的状态,这样即便服务可能被 kill 掉或是重启,但是由于数据保存在 PV 中,所以这些状态也不会丢失。它们之间的关系如下图所示:

在前面讲解 Deployment 时,直接在 Pod template 中定义存储卷,所有副本集使用同一个存储卷,数据都是相同的。但是 StatefulSet 中要求有状态存储,也就意味着数据不一样,每个节点必须有专有存储卷,不能使用相同存储卷,因此需要使用 volumeClaimTemplates,为每个 Pod 生成不同的 PVC,并绑定 PV,这样就实现了 Pod 分别有专属的存储卷。
由于我们这里还没有讲解到关于存储的部分,大家可以先暂时有个大概的印象即可。
- Pod 基本用法
- Pod 简介
- 操作 Pod
- 创建 Pod
- 标签
- 标签选择器
- 命名空间
- 删除及更新 Pod
- 副本集(RS)、后台支撑服务集(DaemonSet)、任务(Job)
- 副本集(RS)
- 后台支撑服务集(DaemonSet)
- 任务(Job)
- 使用 ConfigMap 配置应用程序
- ConfigMap 简介
- 创建 ConfigMap 资源对象
- 通过 YAML 配置文件方式创建
- 通过 kubectl 命令行方式创建
- 通过生成器创建 ConfigMap
- 在 Pod 中使用 ConfigMap
- 通过环境变量方式使用 ConfigMap
- 通过卷挂载(volumeMount)方式使用 ConfigMap
- 使用 Secret 传递敏感数据
- Secret 简介
- 默认令牌 Secret
- 创建 Secret
- 使用 kubectl 创建 Secret
- 使用 YAML 文件手动创建 Secret
- 使用生成器创建 Secret
- 使用 Secrets
- 挂载 Secret 到 Pod 中作为卷进行使用
- 使用 Secret 作为环境变量
- 使用镜像拉取 Secret(ImagePullSecrets)
- 多容器 Pod
- 多容器 Pod 简介
- Pod 中容器间的通信
- Pod 容器共享 Volume
- 进程间通信(IPC)
- 容器间网络通信
- Scheduler
- kube-scheduler 简介
- kube-scheduler 职责及调度流程
- 常用参数
- 预选策略(Predicates Policies)
- 优选策略(Priorites Policies)
- 自定义调度器
- 使用 Deployment 进行 Pod 升级回滚
- Deployment 简介
- Deployment 的升级
- 多重更新(Rollover)
- 更新 Deployment 的标签选择器(Label Selector)
- Deployment 的回滚
- Deployment 的暂停与恢复
- Pod 扩容与缩容
- 手动扩缩容
- 自动扩缩容
- 扩缩容算法
- php-apache 自动扩缩容实例
- 配置 HPA
- v1 版本
- v2beta2 版本
- DaemonSet
- DaemonSet 简介
- 运行示例程序
- 滚动更新
- StatefulSet
- StatefulSet 简介
- 运行 nginx 实例
- 扩缩容 StatefulSet
- 更新 StatefulSet
- 删除 StatefulSet
- 非级联删除
- 级联删除
- Pod 管理策略
- Service 基本用法
- Service 简介
- Service 的类型
- 使用命令创建服务
- 使用 YAML 文件创建服务
- Service Discovery
- 环境变量
- DNS
- ClusterIP Service
- ClusterIp Service 简介
- Normal Service
- YAML 文件模板
- 服务负载分发策略 & 多端口服务 & 端口命名
- 一个简单的例子
- Headless Service
- 无 Selector 的服务
- NodePort Service
- NodePort Service 简介及实例
- 扩展:客户端直接访问 Pod
- hostPort
- hostNetwork
- Port Forward
- LoadBalancer与ExternalName
- LoadBalancer Service 简介
- LoadBalancer Service 实例
- 使用 nginx 软件手动实现负载均衡
- 由云服务商提供负载均衡器
- ExternalName Service 简介
- Ingress
- Ingress 简介
- 部署 nginx-ingress-controller
- 部署一个简单的 Nginx 实例
- 不同的 Ingress 策略配置类型
- 配置 Ingress 处理 TLS 传输
