理解Kubernetes中statefulset是什么

Kubernetes-StatefulSet

StatefulSet 简介

在Kubernetes中,Pod的管理对象RC、Deployment、DaemonSet和Job都是面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如MySQL集群、MongoDB集群、Akka集群、ZooKeeper集群等。

以上集群有几个共同点: 
1.每个节点都有固定的身份ID,通过这个ID,集群中的成员可以互相发现并且通信 
2.集群的规模是比较固定的,集群规模不能随意变动。 
3.集群里的每个节点都是有状态的,通常会持久化数据到永久存储中 
4.如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。

如果用RC/Deployment 控制Pod 副本数的方式来实现上述有状态的集群,则我们会发现第一点是无法满足的,因为Pod的名字是随机产生的,Pod的IP地址也是在运行期才确定且可能有变动的,我们事先无法为每个Pod确定唯一不变的ID。另外,为了能够在其他节点上恢复某个失败的节点,这种集群中的Pod 需要挂载某种共享存储,Kubernetes在1.4版本引入了PetSet这个新资源对象,在1.5更名为"StatefulSet"。StatefulSet 从本质来将,可以看作Deployment/RC 的一种特殊变种

StatefulSet 特点

StatefulSet特点:
1.StatefulSet 里的每个Pod都有稳定、唯一的网络表示,可以用来发现集群内的其他成员。(假设StatefulSet 的名字叫kafka,那么第一个Pod叫kafka-0,第二个Pod叫kafka-1以此类推) 
2.StatefulSet 控制的Pod副本的启动顺序是受控制的,操作第n个Pod,前n-1个Pod已经是运行且准备好的状态 
3.StatefulSet 里的Pod采用稳定的持久化存储卷,通过PV/PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)

StatefulSet是为了解决有状态服务的问题(对应Deployment和Replica Set是为无状态服务而设计),其应用场景包括
   --- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
   --- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
   --- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
   --- 有序收缩,有序删除(即从N-1到0)
   
从上面的应用场景可以发现,StatefulSet由以下几个部分组成:
   --- 用于定义网络标志(DNS domain)的Headless Service
   --- 用于创建PersistentVolumes的volumeClaimTemplates
   --- 定义具体应用的StatefulSet
   
StatefulSet 原理
StatefulSet由Service和volumeClaimTemplates组成。Service中的多个Pod将会被分别编号,并挂载volumeClaimTemplates中声明的PV。

注意: 官方提示StatefulSets()在1.9中是稳定的
案例:K8s企业实践使用storageclass实现动态存储
StatefulSet 除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless Service配合使用,在每个StatfulSet的定义中要声明它属于哪个Headless Service.Headless Service 与普通Service的关键区别在于, Headless Service它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该Service对应的全部Pod的Endpoint列表。

StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实力创建了一个DNS域名,这个域名的格式为: ${podname}.${headless service name}

比如一个3节点的Kafka的StatefulSet集群,对应的Headless Service的名字为kafka,StatefulSet的名字为kafka,则StatefulSet 里面的3个Pod的DNS分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称可以直接在集群的配置文件中固定下来。

简单点说:没有部署HeadlessService的话,PetSet/StatefulSet下的pod,无法通过域名进行访问。

实例演示
地址
https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/
首先使用以下示例创建StatefulSet以一个简单的nginx服务web.yaml为例

StatefulSet注意事项
   --- 还在beta状态,需要kubernetes v1.5版本以上才支持
   --- 所有Pod的Volume必须使用PersistentVolume或者是管理员事先创建好
   --- 为了保证数据安全,删除StatefulSet时不会删除Volume
   --- StatefulSet需要一个Headless Service来定义DNS domain,需要在StatefulSet之前创建好
   --- 目前StatefulSet还没有feature complete,比如更新操作还需要手动patch。
   
案例开始

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:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80

[root@kubernetes-m media]# kubectl apply -f statefulset.yaml 
service/nginx created
statefulset.apps/web created

# 查看创建的headless service和statefulset
[root@kubernetes-m media]# kubectl get svc nginx 
NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   None         <none>        80/TCP    27s

[root@kubernetes-m media]# kubectl get statefulset web 
NAME   READY   AGE
web    2/2     99s

# 查看创建的Pod,他们都是有序的
[root@kubernetes-m media]# kubectl get pods -l app=nginx
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          2m17s
web-1   1/1     Running   0          2m16s

# 使用nslookup查看这些Pod的DNS
[root@kubernetes-m media]# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh
/ # nslookup web-0.nginx

/ # nslookup web-0.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx
Address 1: 10.244.2.10
/ # nslookup web-1.nginx
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-1.nginx
Address 1: 10.244.3.12
/ # nslookup web-0.nginx.default.svc.cluster.local
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

Name:      web-0.nginx.default.svc.cluster.local
Address 1: 10.244.2.10

Statefulset 扩容与缩容

# 扩容
$ kubectl scale statefulset web --replicas=5

# 缩容
$ kubectl patch statefulset web -p '{"spec":{"replicas":3}}'

# 镜像更新(目前还不支持直接更新image,需要patch来间接实现)
$ kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.7"}]'

# 删除StatefulSet和Headless Service
$ kubectl delete statefulset web
$ kubectl delete service nginx

# StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除
$ kubectl delete pvc www-web-0 www-web-1
posted @ 2021-12-17 11:13  Layzer  阅读(45)  评论(0编辑  收藏  举报