《Kubernetes知识篇:Kubernetes之Statefulset控制器》

文章目录

  • 一、Statefulset概述
    • 1.1、有状态服务与无状态服务
    • 1.2、Statefulset典型的应用场景
    • 1.3、StatefulSet组成部分
    • 1.4、为什么要有headless?
    • 1.5、为什么要有volumeClainTemplate?
  • 二、Statefulset资源清单文件详解
    • 2.1、Pod管理策略
    • 2.2、Pod更新策略
  • 三、Statefulset使用案例
    • 3.1、使用nfs-client实现storageclass
    • 3.2、StatefulSet创建
    • 3.3、验证解析
    • 3.4、验证存储
  • 四、Statefulset管理Pod
    • 4.1、扩容
    • 4.2、缩容
    • 4.3、更新
  • 总结:整理不易,如果对你有帮助,可否点赞关注一下?


一、Statefulset概述

官网:StatefulSets

1.1、有状态服务与无状态服务

StatefulSet就是为了解决有状态服务的问题而设计的,对应Deployments和ReplicaSets是为无状态服务而设计一样。

有状态服务?
有状态服务是指需要数据存储功能的服务、或者指多线程类型的服务,队列等。StatefulSet就是用来管理有状态的服务的,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等。

无状态服务?
ReplicaSet、DaemonSet、Deployment等,由于是无状态服务,所以这些控制器创建的pod序号都是随机值。并且在缩容的时候并不会明确缩容某一个pod,而是随机的,因为所有实例对于同一个请求响应的结果是完全一致的,所以缩容任何一个pod都可以,比如nginx实例,tomcat实例等。


1.2、Statefulset典型的应用场景

Statefulset典型的应用场景包括:
1、稳定的不共享持久化存储:即每个pod的存储资源是不共享的,且pod重新调度后还是能访问到相同的持久化数据,基于pvc实现。
2、稳定的网络标志:即pod重新调度后其PodName和HostName不变,且PodName和HostName是相同的,基于Headless Service来实现的。
3、有序部署,有序扩展:即pod是有顺序的,在部署或者扩展的时候是根据定义的顺序依次依序部署的(即从0到N-1,在下一个Pod运行之前所有之前的pod必都是Running状态或者Ready状态),是基于init containers来实现的。
4、有序收缩:在pod删除时是从最后一个依次往前删除,即从N-1到0。


1.3、StatefulSet组成部分

在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

从上面的应用场景可以发现,StatefulSet由以下几个部分组成:
1、Headless Service(无头服务)用于为Pod资源标识符生成可解析的DNS记录。
2、volumeClaimTemplates (存储卷申请模板)基于静态或动态PV供给方式为Pod资源提供专有的固定存储。
3、StatefulSet,用于管控Pod资源。


1.4、为什么要有headless?

Headless service不分配clusterIP,headless service可以通过解析service的DNS,返回所有Pod的dns和ip地址 (statefulSet部署的Pod才有DNS),普通的service,只能通过解析service的DNS返回service的ClusterIP。

headless service会为service分配一个域名

$<service name>.$<namespace name>.svc.cluster.local

StatefulSet会为关联的Pod分配一个dnsName

$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local

FQDN全称Fully Qualified Domain Name

即全限定域名:同时带有主机名和域名的名称
FQDN = Hostname + DomainName
例如:
主机名是 k8s-worker-16,域名是baidu.com,则FQDN=k8s-worker-16.baidu.com

在deployment中,每一个pod是没有名称,是随机字符串,是无序的。而statefulset中是要求有序的,每一个pod的名称必须是固定的。当节点挂了,重建之后的标识符是不变的,每一个节点的节点名称是不能改变的。pod名称是作为pod识别的唯一标识符,必须保证其标识符的稳定并且唯一。这时候要用到无头服务,它可以给每个Pod一个唯一的名称。


1.5、为什么要有volumeClainTemplate?

大部分有状态副本集都会用到持久存储,比如分布式系统来说,由于数据是不一样的,每个节点都需要自己专用的存储节点。而在deployment中pod模板中创建的存储卷是一个共享的存储卷,多个pod使用同一个存储卷,而statefulset定义中的每一个pod都不能使用同一个存储卷,由此基于pod模板创建pod是不适应的,这就需要引入volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而请求绑定一个PV,从而有自己专用的存储卷。Pod名称、PVC和PV关系图如下:
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第1张图片


二、Statefulset资源清单文件详解

[root@k8s-client-17 ~]# kubectl explain sts.spec
KIND:     StatefulSet
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec defines the desired identities of pods in this set.

     A StatefulSetSpec is the specification of a StatefulSet.

FIELDS:
   podManagementPolicy	<string>  #pod管理策略
   replicas	<integer> #副本数
   revisionHistoryLimit	<integer> #保留的历史版本
   selector	<Object> -required- #标签选择器,选择它所关联的pod
   serviceName	<string> -required- #headless service的名字
   template	<Object> -required- #生成pod的模板
   updateStrategy	<Object> #更新策略
   volumeClaimTemplates	<[]Object> #存储卷申请模板

2.1、Pod管理策略

pod管理策略
1、OrderedReady:默认方式,按照pod的次序依次创建每个pod并等待ready之后才创建后面的pod。
2、Parallel:并行创建或删除pod,和deployment类型的pod一样,不等待前面的pod ready就开始创建所有的pod。


2.2、Pod更新策略

在Kubernetes 1.7之后,运行通过配置StatefulSet的.spec.updateStrategy,实现Pod的容器、标签、资源请求/限制和注释自动更新。
1、OnDelete更新策略是1.6之前版本的行为。默认的向后兼容更新策略. 只有当你手动删除老的DaemonSet pods时,新的DaemonSet pods 才会被自动创建。
2、RollingUpdate更新策略将实现StatefulSet中Pod的自动滚动更新,老的DaemonSet pods会被自动杀死,新的DaemonSet pods会自动创建。,这是StatefulSet的默认更新模式。如果.spec.updateStrategy.type设置为 RollingUpdate,则StatefulSet控制器将会删除和重建StatefulSet中的每一Pod。它将会按照从最大到最小的序数终止Pod,并按照从小到大顺序重建Pod。


三、Statefulset使用案例

3.1、使用nfs-client实现storageclass

使用nfs-client实现storageclass《第七章》


3.2、StatefulSet创建

apiVersion: v1
kind: Service
metadata: 
  name: svc-nginx
  labels:
     app: nginx
spec:
  ports:
  - port: 8088
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata: 
  name: sts-nginx
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "svc-nginx" #必须与上面定义的service名称保持一致
  replicas: 3
  template:
    metadata: 
     labels:
       app: nginx
    spec: 
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: webport
        volumeMounts:
        - name: html #必须与下面定义的volumeClaimTemplates.metadata.name字段的html保持一致
          mountPath: /usr/share/nginx/html #容器里挂载目录
  volumeClaimTemplates:
  - metadata:
      name: html
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi
      storageClassName: managed-nfs-storage #这里定义的storageClass要与之前创建的class名称保持一致

注意:该headless类型service和clusterIp类型的serivice有明显区别,spec下是clusterIp: None

1、观察pod的创建,会发现是有序创建,从0-N的顺序开始创建,pod的名称是:StatefulSet名称+【0-N】序号。
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第2张图片
2、观察pod的删除,会发现是有序删除,从N-0的倒序顺序开始删除。
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第3张图片
3、查看storageclass,pv,pvc,pod,statefulset,svc
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第4张图片
4、每个Pod都拥有一个基于其顺序索引的稳定的主机名
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第5张图片


3.3、验证解析

使用带有nslookup命令的busybox镜像启动一个Pod,检查集群内的DNS地址设置。

kubectl run busybox --image busybox:1.28.4 --restart=Never --rm -it busybox -- sh

注意:这里使用busybox的镜像版本建议小于或等于1.28.4,查了相关资料说是官方的bug,否则会出现Can’t find svc-nginx.default.svc.cluster.local: No answer类似报错。

查询service dns,会把对应的pod ip解析出来,如下图所示:
在这里插入图片描述
statefulset创建的pod也是有dns记录的,如下图所示:
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第6张图片


3.4、验证存储

将pod 的主机名写入它们的index.html文件并验证nginx web 服务器使用该主机名提供服务

[root@k8s-client-17 state]# kubectl exec -it sts-nginx-0 -- /bin/sh
# echo $(hostname) > /usr/share/nginx/html/index.html
# exit

[root@k8s-client-17 state]# kubectl exec -it sts-nginx-1 -- /bin/sh
# echo $(hostname) > /usr/share/nginx/html/index.html
# exit

[root@k8s-client-17 state]# kubectl exec -it sts-nginx-2 -- /bin/sh
# echo $(hostname) > /usr/share/nginx/html/index.html

查看pod的ip地址
在这里插入图片描述
通过curl访问pod中nginx服务,结果如下:
在这里插入图片描述
重启pod,pod的ip发生了变化
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第7张图片
再次通过curl访问pod中nginx服务,访问结果还是一样,结果如下:
在这里插入图片描述
总结:虽然sts-nginx-0 、sts-nginx-1和sts-nginx-2被重新调度了,但它们仍然继续监听各自的主机名,因为和它们的PersistentVolumeClaim相关联的PersistentVolume被重新挂载到了各自的volumeMount上。不管sts-nginx-0 、sts-nginx-1和sts-nginx-2被调度到了哪个节点上,它们的PersistentVolumes将会被挂载到合适的挂载点上。


四、Statefulset管理Pod

4.1、扩容

方法一:修改配置文件statefulset.yaml里的replicas的值即可,原来replicas: 3,现在变成replicaset: 4,修改之后,执行如下命令更新

[root@k8s-client-17 state]# kubectl apply -f statefulset.yaml

pod的数量从3个变成4个,pod的名称按照【0-N】规则递增,如下图所示:
在这里插入图片描述
方法二:直接编辑控制器实现扩容,修改replicas的值即可,原来replicas: 3,现在变成replicaset: 4,这个是我们把请求提交给了apiserver,实现实时修改

[root@k8s-client-17 state]# kubectl get statefulset
NAME        READY   AGE
sts-nginx   3/3     16h
[root@k8s-client-17 state]# kubectl edit statefulset sts-nginx

pod的数量从3个变成4个,pod的名称按照【0-N】规则递增,如下图所示:
在这里插入图片描述
方法三:使用kubectl scale 或者kubectl patch来扩容一个 StatefulSet

[root@k8s-client-17 state]# kubectl scale statefulset sts-nginx --replicas=4 -n default
statefulset.apps/sts-nginx scaled
或
[root@k8s-client-17 state]# kubectl patch statefulset sts-nginx -p '{"spec":{"replicas":4}}' -n default
statefulset.apps/sts-nginx patch

pod的数量从3个变成4个,pod的名称按照【0-N】规则递增,如下图所示:
在这里插入图片描述


4.2、缩容

方法一:修改配置文件statefulset.yaml里的replicas的值即可,原来replicas: 3,现在变成replicaset: 2,修改之后,执行如下命令更新

[root@k8s-client-17 state]# kubectl apply -f statefulset.yaml

pod的数量从3个变成2个,pod的名称按照【N-0】规则递j减,如下图所示:
在这里插入图片描述
方法二:直接编辑控制器实现扩容,修改replicas的值即可,原来replicas: 3,现在变成replicaset: 2,这个是我们把请求提交给了apiserver,实现实时修改

[root@k8s-client-17 state]# kubectl get statefulset
NAME        READY   AGE
sts-nginx   3/3     16h
[root@k8s-client-17 state]# kubectl edit statefulset sts-nginx

pod的数量从3个变成2个,pod的名称按照【N-0】规则递j减,如下图所示:
在这里插入图片描述
方法三:使用kubectl scale或者kubectl patch来缩容一个 StatefulSet

[root@k8s-client-17 state]# kubectl scale statefulset sts-nginx --replicas=2 -n default
statefulset.apps/sts-nginx scaled
或
[root@k8s-client-17 state]# kubectl patch statefulset sts-nginx -p '{"spec":{"replicas":2}}' -n default
statefulset.apps/sts-nginx patch

pod的数量从3个变成2个,pod的名称按照【N-0】规则递j减,如下图所示:
在这里插入图片描述
总结:扩容时,如果pv是动态的storageclass的话,pvc同样会增加,但当缩容时,pvc并不会自定的删除,如下图所示:
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第8张图片


4.3、更新

方法一:修改配置文件statefulset.yaml里的image的值即可,原来image: nginx:1.14.1,现在变成image: nginx:1.16.1,修改之后,执行如下命令更新

[root@k8s-client-17 state]# kubectl apply -f statefulset.yaml

如下图所示,则表示更新成功:
《Kubernetes知识篇:Kubernetes之Statefulset控制器》_第9张图片


总结:整理不易,如果对你有帮助,可否点赞关注一下?

更多详细内容请参考:企业级K8s集群运维实战

你可能感兴趣的:(《企业级K8s集群运维实战》,kubernetes,运维,运维开发)