K8S StatefulSet
清空K8S对象
为了避免之前学习的内容造成的影响,先手动把K8S集群中的所有对象清空,使用一个全新的环境来学习StatefulSet的基本使用。
查看对象
- 查看service对象
kubectl get services
- 查看ReplicaSet对象
kubectl get rs
- 查看Replication Controller对象
kubectl get rc
还有其他K8S对象,就不一一罗列展示了
清空对象
- 方法一 删除命名空间内所有的对象
# 1. 删除指定命名空间的所有对象
# kubectl delete all --all -n {namespace}
# 2. 删除默认命名空间(default) 所有对象
# kubectl delete all --all
kubectl delete all --all
- 方法二 - 用户可以删除命名空间,然后重建
# 1. 删除命名空间
# kubectl delete namespace {namespace}
# 2. 重建命名空间
# kubectl create namespace {namespace}
注意:默认的命名空间不能删除,清空完毕后可以使用命令查看验证对象是否存在,如查看Pod对象
kubectl get pods
StatefulSet 基本概念
StatefulSet(有状态集)长用于部署有状态的应用程序,跟Deployment类似StatefulSet也可以管理多个Pod集群,不同的是StatefulSet为每一个Pod分配一个唯一的粘性标识。并管理Pod的扩容,并为每一个Pod赋予一个有序的Pod名称。如定义一个名为Redis的StatefulSet集群,指定三个Pod,那么创建出来的Pod名称就会为Redis-0、Redis-1、Redis-2.
如果想使用存储卷提供数据持久化服务,可以使用StatefulSet作为整体解决方案的一部分。尽管StatefulSet的单个Pod容易发生故障,但是持久Pod对象可以很容易的使存储卷匹配任何新创建的Pod对象。
使用指导
StatefulSet适用于以下需求的应用程序:
- 稳定、唯一的网络标识
- 稳定、持久话的数据存储
- 有序、优雅的部署、扩容
- 有序、自动滚动更新功能
如果应用程序并不要任何稳定的标识符、顺序部署、扩容扩展;应该使用无状态的K8S对象进行系统部署,如Deployment 或者 ReplicaSet。
使用限制
- Pod 配置的存储必须根据实际需求使用 PersistentVolume Provisioner 进行定义,或者由管理员进行预分配
- 删除、扩容StatefulSet 并不会删除关联的存储卷,其目的是 确保存储卷的数据安全
- StatefulSet 需要 Headless Service 服务来创建Pod网络表示,开发者负责创建此服务
- StatefulSet 不保证在删除StatefulSet时终止Pod,目的是为了实现有序、优雅停止Pod,可以在删除之前将集群数量设置为0
- 当使用Pod默认管理策略(OrderedReady)进行滚动更新时,可能会进入需要手动干预才能修复的损坏状态
演示案例
配置文件
#vim StatefulSet.yaml 内容如下
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
minReadySeconds: 10 # by default is 0
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: web
配置说明:
- 定义一个名为nginx的Headless Service服务,用于控制网络服务
- 定义一个名为web的StatefulSet对象,关联3个nginx容器,每个启动的容器有用唯一的名称
- ClaimTemplates 使用PersistentVolumes提供稳定的存储功能
启动服务
- 创建StatefulSet对象
kubectl apply -f StatefulSet.yaml
- 检查新创建的StatefulSet对象
kubectl get sts
- 检查关联的Pod对象
kubectl get pods
请细看以上Pod名称按照顺序从0到2开始,组成三个Pods集群。三个Pod按顺序启动,后续的Pod启动必须在前面Pod启动之后再启动,因此以上三个Pod的启动顺序为:web-0 > web-1 > web-2
- 查看关联的Service对象
kubectl get svc
Pod Selector
在StatefulSet中必须设置Pod选择器(.spec.selector)用来匹配器标签(.spec.template.metadata.labels),如果未指定匹配的Pod Selector 将导致StatefulSet在创建期间出现验证错误。
Minimum ready seconds
.spec.minReadySeconds是一个可选字段,默认值为0(Pod一准备就绪就被视为可用). 用于指定新创建的Pod在没有任何容器奔溃的情况下运行和准备就绪的最短秒数,以便将其视为可用。用于在使用滚动更新时检查更新进度
启动流程
StatefulSet管理的Pod部署和扩展规则如下:
- 对于N个副本StatefulSet对象,将按照顺序从0到N-1开始创建Pod
- 当删除Pod时,按照N-1到0逆序终止Pod
- 在扩容伸缩Pod之前,必须保证之前的Pod处于Running状态
- 在终止Pod之前,必须保证他它后续的Pod完全关闭
定义StatefulSet时,不应将参数 pod.Spec.TerminationGracePeriodSeconds指定为0,这种方式存在安全隐患,不鼓励使用。
当创建上面的Nginx实例时,将按照web-0、web-1、web-2的顺序部署三个Pod。在web-0处于Running或者Ready之前,web-1不会被创建;同理,web-2在web-1位处于Running状态之前不会被部署。如果web-1处于Running、Ready状态时,web-0变成Failed状态,那么web-2不会被启动,直到web-0恢复为Running状态。
如果用户将StatefulSet的replicas副本数设置为1,那么web-2首先将被终止,在web-2完全关闭之前,不会删除web-1.如果web-2终止关闭后,web-0突然失败,那么在web-0未恢复成Running状态前,web-1不会被删除
扩容伸缩
和Deployment一样,可以更过更新replicas字段扩容/伸缩StatefulSet,也可以使用kubectl scale、kubectl edit、kubectl patch来扩容/伸StatefulSet对象。
集群扩容
kubectl scale sts web --replicas=5
重新检查StatsfulSet 对象状态
kubectl get sts
重新检查扩容后Pod的数量及状态
kubectl get pod
根据上述几个图片显示web的节点从3变成了5,由此完成扩容。
集群缩容
使用patch命令将副本数重新设置为3
kubectl patch sts web -p '{"spec":{"replicas":3}}'
检查StatefulSet及其关联的Pod对象状态
StatefulSet 更新策略
StatefulSet也提供了多种更新策略,可以在**.spec.updateStrategy**指定更新策略。
OnDelete
当StatefulSet的.spec.updateStrategy.type设置为OnDelete时,StatefulSet控制器将不会自动更新StatefulSet中的Pod。用户必须手动删除Pod以使控制器创建新的Pod。
RollingUpdate
RollingUpdate更新策略自动更新StatefulSet中所有Pod的自动滚动更,这是默认的更新策略。采用与序号索引相反的顺序进行滚动更新。
- 更新StatefulSet更新策略
比如更新一个名称为web的StatefulSet的使用RollingUpdate方式更新
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
- 查看更改后的StatefulSet
kubectl get sts web -o yaml | grep -A 1 "updateStrategy"
分段更新
Stateful可以使用RollingUpdate更新策略的partition参数来分段更新StatefulSet。分段更新将会使Stateful中其余的所有Pod(序号小于分区)保持当前版本,只更新序号大于等于分区的Pod,利用此特性可以简单实现金丝雀发布(灰色发布)
比如定义一个分区为3,可以使用patch直接对StatefulSet进行设置
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
删除Pod触发更新
kubectl delete po web-2
由于,web-2的需要小区分区3,所以Pod不会被更新,还是会使用以前的容器恢复Pod。
将分区改为1,此时会自动更新web-2,但不会更新web-0、web-1, 重新执行以上删除命令,如下图由于集群需要维护指定数量的副本,因此重新创建了一个web-2.
StatefulSet 删除
删除StatefulSet有两种方式,级联删除和非级联删除。使用非级联方式删除StatefulSet对象时,Stateful的Pod不会被删除;使用级联方式删除StatefulSet时,StatefulSet和它关联的pod都会被删除
非级联删除
# 使用以下命令进行非级联删除
kubectl delete statefulset web --cascade=false
此时三个Pod对象无法管理到StatefulSet对象,因此只能被手动删除,删除时也不会被重建
级联删除
# 1. 重新创建StatefulSet集群
kubectl apply -f StatefulSet.yaml
# 2. 检查Stateful及关联对象
# 使用以下命令进行级联删除 去掉--cascade=false即可
kubectl delete statefulset web