十六. Kubernetes 工作负载 之 StatefulSet
目录
一. StatefulSet 基础解释
- Deployment部署的应用一般称为无状态应用,StatefulSet部署的应用一般称为有状态应用
- 无状态应用:可以简单理解为无状态应用不会记录当前状态,例如网络,存储等信息,如果应用宕机重启,重启后网络,存储,顺序可能等可能会变,例如Deployment部署的业务代码
- 有状态应用:可以记录当前状态,即使重启,重启后根据状态记录信息可以做到网络,存储,顺序等不变,例如中间件MySQL、Redis、MQ等等,以mysql为例,部署为有状态的服务,即使宕机重启访问地址不会变,其它服务还是可以正常访问的
- 并且使用StatefulSet部署的服务是有顺序的,创建pod时,会给创建的多个pod添加索引,部署,启动等都是按照这个索引顺序进行,停止或删除是按照索引逆序执行
- StatefulSet 使用场景总结:
- 稳定、唯一的网络标识(dnsname)必须配合Service使用,StatefulSet通过与其相关的无头服务Service为每个pod提供DNS解析条目,通过解析DNS解析条目访问pod
- 稳定的、持久的存储, 每个Pod始终对应各自的存储路径(PersistantVolumeClaimTemplate)
- 有序的、优雅的部署和缩放。按顺序地增加副本、减少副本,并在减少副本时执行清理
- 有序的、自动的滚动更新。按顺序自动地执行滚动更新
- StatefulSet注意点
- 给定 Pod 的存储必须由 PersistentVolume 驱动 基于所请求的 storage class 来提供,或者由管理员预先提供。
- 删除或者收缩 StatefulSet 并不会 删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。
- StatefulSet 当前需要无头服务 来负责 Pod 的网络标识。你需要负责创建此服务。
- 当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的Pod 可以有序地且体面地终止,可以在删除之前将 StatefulSet 缩放为 0。
- 在默认 Pod 管理策略( OrderedReady ) 时使用 滚动更新,可能进入需要人工干预 才能修复的损坏状态
二. StatefulSet 配合 Service 负载均衡网络(无头服务)的使用
- StatefulSe与Service负载均衡网络的配合,使用StatefulSet 部署的有状态应用网络,存储等信息不变,以访问地址不变为例,封装Service负载均衡网络时设置" clusterIP: None" 不要分配ClusterIP,headless service等,访问地址由Service内部代理的通过StatefulSe部署pod自己控制
- 该方式下k8s内部通过"podName.serviceName.namespace.svc.cluster.local" 访问指定pod
- 通过无头服务Service代理StatefulSet 部署的多个pod,也是可以直接访问service,通过Service负载均衡选择指定pod访问
- 此时外部无法访问这个无头服务Service的,如果想要外部访问需要使用ingress网络定义所有的访问逻辑
- 一个StatefulSet与Service示例:(下方解释)
- 下方使用StatefulSet部署mysql服务,部署3个副本,pod名称为none-mysql,并使用serviceName将当前部署的服务添加到none-service负载均衡网络中
- 封装Service负载均衡网络"none-service",通过"clusterIP: None"设置当前Service为无头服务,不分配ClusterIP,headless等
- 由于使用StatefulSet部署时,会给部署的多个pod添加索引,加上索引后每个pod名称都是唯一的,例如"none-mysql-0",“none-mysql-1”,“none-mysql-2”,内部管理的多个pod启停删除等都是由顺序的,访问ip也是固定的,即使pod重启也不会变
- 部署的服务添加到无头的负载均衡网络后,通过"podName.serviceName.namespace.svc.cluster.local"访问指定pod(后面的".svc.cluster.local"是固定格式),换算下来如果想要访问none-mysql第一个pod,请求"none-mysql-0.none-service.default.svc.cluster.local"即可
apiVersion: apps/v1
kind: StatefulSet ### 有状态副本集
metadata:
name: stateful-mysql
namespace: default
spec:
selector:
matchLabels:
app: none-mysql
serviceName: "none-service" ## 服务名,指定加到那个service里面
replicas: 3 # 三个副本
template: ## Pod模板
metadata:
labels:
app: none-mysql
spec:
containers:
- name: none-mysql
image: mysql
---
#负载均衡网络
apiVersion: v1
kind: Service
metadata:
name: none-service ## 和部署的服务serviceName值与此处相同表示加入到当前网络中
namespace: default
spec:
selector:
app: none-mysql #选中哪些pod的标签
clusterIP: None ## 设置为None 表示当前是一个无头服务,不要分配ClusterIP,headless service,整个集群的Pod能直接访问,注意此时浏览器目前不能访问,如果想要外部访问时需要使用ingress网络定义所有的访问逻辑
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
podManagementPolicy: pod的管理策略
- 在使用StatefulSet 部署时,提供了一个podManagementPolicy属性,用来控制Pod创建,升级以及扩缩容逻辑,可以设置为:
- OrderedReady: 按需(默认值,有序启动,StatefulSet部署时会给每个pod提供一个索引,会按照这个索引顺序启动,索引逆序停止)
- Parallel:并发(同时创建启动,一般不使用)
updateStrategy: pod更新策略
- 在使用StatefulSet 部署时,提供了一个updateStrategy属性,用来控制更新策略,是一个属性对象,内部有rollingUpdate和type两个属性,默认情况下使用RollingUpdate滚动升级作为更新策略,可以指定为partition按分区升级
使用StatefulSet时,会给部署的pod添加索引,在指定为partition更新策略,更新时只会更新索引大于等于partition的pod
apiVersion: apps/v1
kind: StatefulSet #有状态副本集
metadata:
name: stateful-nginx
namespace: default
spec:
podManagementPolicy: OrderedReady #所有Pod一起创建,OrderedReady:有序创建
updateStrategy: #升级策略
rollingUpdate:
partition: 1 #更新大于等于这个索引的pod
selector:
matchLabels:
app: ss-nginx #hastomatch.spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 #三个副本
template: #Pod模板
metadata:
labels:
app: ss-nginx
spec:
containers:
- name: nginx
image: nginx