千家信息网

Kubernetes针对有状态服务数据持久化之Statefu

发表于:2024-10-21 作者:千家信息网编辑
千家信息网最后更新 2024年10月21日,一、Kubernetes无状态服务VS有状态服务1)Kubernetes无状态服务Kubernetes无状态服务特征:1)是指该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一请求响
千家信息网最后更新 2024年10月21日Kubernetes针对有状态服务数据持久化之Statefu

一、Kubernetes无状态服务VS有状态服务

1)Kubernetes无状态服务

Kubernetes无状态服务特征:
1)是指该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一请求响应的结果是完全一致的;
2)多个实例可以共享相同的持久化数据。例如:nginx实例、tomcat实例等;
3)相关的Kubernetes资源有:ReplicaSet、ReplicationController、Deployment等,由于是无状态服务,所以这些控制器创建的Pod名称都是随机性的。并且在缩容时并不会明确缩容某一个Pod,而是随机的,因为所有实例得到的返回值都是一样的,所以缩容任何一个Pod都可以;

2)Kubernetes有状态服务

Kubernetes有状态服务特征:
1)有状态服务可以说是需要数据存储功能的服务、或者指多线程类型的服务、队列等。(比如:mysql数据库、kafka、zookeeper等);
2)每个实例都需要自己独立的持久化存储,并且在Kubernetes中通过声明模板的方式来进行定义。持久卷声明模板在创建pod之前创建,绑定到pod中,模板可以定义多个;
3)相关的Kubernetes资源有:StatefulSet。由于是有状态的服务,所以每个Pod都有特定的名称和网络标识。比如Pod名称是由StatefulSet名+有序的数字组成(0、1、2……);
4)在进行缩容操作时,可以明确知道会缩容那一个Pod,从数字最大的开始。并且StatefulSet在已有实例不健康的情况下是不允许做缩容操作的;

3)无状态服务和有状态服务的区别

主要表现在以下方面:
1)实例数量:无状态服务可以有一个或多个实例,因此支持两种服务容量调节模式;有状态服务职能有一个实例,不允许创建多个实例,因此也不支持服务容量的调节;
2)存储卷:无状态服务可以有存储卷,也可以没有,即使有也无法备份存储卷中的数据;有状态服务必须要有存储卷,并且在创建服务时,必须指定该存储卷分配的磁盘空间大小;
3)数据存储: 无状态服务运行过程中的所有数据(除日志和监控数据)都存在容器实例里的文件系统中,如果实例停止或者删除,则这些数据都将丢失,无法找回;而对于有状态服务,凡是已经挂载了存储卷的目录下的文件内容都可以随时进行备份,备份的数据可以下载,也可以用于恢复新的服务。但对于没有挂载卷的目录下的数据,仍然是无法备份和保存的,如果实例停止或者删除,这些非挂载卷里的文件内容同样会丢失。

4)StatefulSet概述

StatefulSet是Kubernetes提供的管理有状态应用的负载管理控制器API。在Pods管理的基础上,保证Pods的顺序和一致性。与Deployment一样,StatefulSet也是使用容器的Spec来创建Pod,与之不同StatefulSet创建的Pods在生命周期中会保持持久的标记(例如Pod Name)。

5)StatefulSet特点

1)稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现;
2)稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现;
3)有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现;
4)有序收缩,有序删除(即从N-1到0);

二、使用StatefulSet实现自动创建PVC

1)搭建NFS共享存储

为了方便,就直接在master节点上部署NFS存储了!

[root@master ~]# yum -y install nfs-utils rpcbind[root@master ~]# vim /etc/exports/nfsdata *(rw,sync,no_root_squash)[root@master ~]# mkdir /nfsdata[root@master ~]# systemctl start nfs-server[root@master ~]# systemctl start rpcbind[root@master ~]# showmount -eExport list for master:/nfsdata *

2)创建rbac授权

[root@master ~]# vim rbac-rolebind.yamlapiVersion: v1                            #创建一个用于认证的服务账号kind: ServiceAccountmetadata:  name: nfs-provisioner---apiVersion: rbac.authorization.k8s.io/v1        #创建群集规则kind: ClusterRolemetadata:  name: nfs-provisioner-runnerrules:   -  apiGroups: [""]      resources: ["persistentvolumes"]      verbs: ["get", "list", "watch", "create", "delete"]   -  apiGroups: [""]      resources: ["persistentvolumeclaims"]      verbs: ["get", "list", "watch", "update"]   -  apiGroups: ["storage.k8s.io"]      resources: ["storageclasses"]      verbs: ["get", "list", "watch"]   -  apiGroups: [""]      resources: ["events"]      verbs: ["watch", "create", "update", "patch"]   -  apiGroups: [""]      resources: ["services", "endpoints"]      verbs: ["get","create","list", "watch","update"]   -  apiGroups: ["extensions"]      resources: ["podsecuritypolicies"]      resourceNames: ["nfs-provisioner"]      verbs: ["use"]---kind: ClusterRoleBinding                #将服务认证用户与群集规则进行绑定apiVersion: rbac.authorization.k8s.io/v1metadata:  name: run-nfs-provisionersubjects:  - kind: ServiceAccount    name: nfs-provisioner    namespace: default                    #必写字段,否则会提示错误roleRef:  kind: ClusterRole  name: nfs-provisioner-runner  apiGroup: rbac.authorization.k8s.io[root@master ~]# kubectl apply -f rbac-rolebind.yaml    

3)创建nfs-deployment.资源

[root@master ~]# vim nfs-deployment.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: nfs-client-provisionerspec:  replicas: 1                              #指定副本数量为1  strategy:    type: Recreate                      #指定策略类型为重置  template:    metadata:      labels:        app: nfs-client-provisioner    spec:      serviceAccount: nfs-provisioner            #指定rbac yanl文件中创建的认证用户账号      containers:        - name: nfs-client-provisioner          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner     #使用的镜像           volumeMounts:            - name: nfs-client-root              mountPath:  /persistentvolumes             #指定容器内挂载的目录          env:            - name: PROVISIONER_NAME           #容器内的变量用于指定提供存储的名称              value: lzj            - name: NFS_SERVER                      #容器内的变量用于指定nfs服务的IP地址              value: 192.168.1.1            - name: NFS_PATH                       #容器内的变量指定nfs服务器对应的目录              value: /nfsdata      volumes:                                                #指定挂载到容器内的nfs的路径及IP        - name: nfs-client-root          nfs:            server: 192.168.1.1            path: /nfsdata[root@master ~]# kubectl apply -f nfs-deployment.yaml[root@master ~]# kubectl get pod NAME                                      READY   STATUS    RESTARTS   AGEnfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          2m34s

4)创建SC(Storage Class)

[root@master ~]# vim sc.yamlapiVersion: storage.k8s.io/v1kind: StorageClassmetadata:  name: stateful-nfs  namespace: xiaojiang-testprovisioner: lzj                  #这个要和nfs-client-provisioner的env环境变量中的PROVISIONER_NAME的value值对应。reclaimPolicy: Retain               #指定回收策略为Retain(手动释放)[root@master ~]# kubectl apply -f sc.yaml [root@master ~]# kubectl get StorageClassNAME           PROVISIONER   AGEstateful-nfs   lzj           17s

5)创建Pod

[root@master ~]# vim statefulset.yaml apiVersion: v1kind: Servicemetadata:  name: headless-svc                    #从名称就可以是无头服务  labels:    app: headless-svcspec:  ports:  - port: 80    name: myweb  selector:    app: headless-pod  clusterIP: None                        #不分配群集的IP地址,所以不具备负载均衡的能力---apiVersion: apps/v1kind: StatefulSet                          #定义pod中运行的应用metadata:  name: statefulset-testspec:  serviceName: headless-svc  replicas: 3  selector:    matchLabels:      app: headless-pod  template:    metadata:      labels:        app: headless-pod    spec:      containers:      - image: httpd        name: myhttpd        ports:        - containerPort: 80          name: httpd        volumeMounts:        - mountPath: /usr/local/apache2/htdocs          name: test  volumeClaimTemplates:                       #定义创建PVC使用的模板  - metadata:      name: test      annotations:  #这是指定storageclass        volume.beta.kubernetes.io/storage-class: stateful-nfs    spec:      accessModes:        - ReadWriteOnce      resources:        requests:          storage: 100Mi[root@master ~]# kubectl apply -f statefulset.yaml [root@master ~]# kubectl get podNAME                                      READY   STATUS    RESTARTS   AGEnfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          10mstatefulset-test-0                        1/1     Running   0          29sstatefulset-test-1                        1/1     Running   0          18sstatefulset-test-2                        1/1     Running   0          11s[root@master ~]# kubectl get pv[root@master ~]# kubectl get pvc              #PV与PVC已经生成[root@master ~]# ls /nfsdata/default-test-statefulset-test-0-pvc-54d0b06c-698e-4f1a-8327-255b10978cbedefault-test-statefulset-test-1-pvc-1b499d49-a787-4f2b-b238-404b05f75fd7default-test-statefulset-test-2-pvc-7766f8da-6f3b-4c1f-9eb8-dfadda1e656f[root@master ~]# echo "hello world" > /nfsdata/default-test-statefulset-test-0-pvc-54d0b06c-698e-4f1a-8327-255b10978cbe/index.html[root@master ~]# kubectl get pod -o wide | grep test-0statefulset-test-0                        1/1     Running   0          4m53s   10.244.2.4   node02              [root@master ~]# curl 10.244.2.4hello world[root@master ~]# curl -I 10.244.2.4HTTP/1.1 200 OKDate: Wed, 12 Feb 2020 09:52:04 GMTServer: Apache/2.4.41 (Unix)Last-Modified: Wed, 12 Feb 2020 09:45:37 GMTETag: "c-59e5dd5ac0a63"Accept-Ranges: bytesContent-Length: 12Content-Type: text/html#可以看出现在提供web页面的服务是Apache

6)对pod进行更新并扩容

[root@master ~]# vim statefulset.yaml apiVersion: v1kind: Servicemetadata:  name: headless-svc  labels:    app: headless-svcspec:  ports:  - port: 80    name: myweb  selector:    app: headless-pod  clusterIP: None---apiVersion: apps/v1kind: StatefulSetmetadata:  name: statefulset-testspec:  updateStrategy:    rollingUpdate:      partition: 2                           #指定并行升级的个数  serviceName: headless-svc  replicas: 10  selector:    matchLabels:      app: headless-pod  template:    metadata:      labels:        app: headless-pod    spec:      containers:      - image: nginx                       #更换扩容时使用的镜像        name: myhttpd        ports:        - containerPort: 80          name: httpd        volumeMounts:        - mountPath: /usr/share/nginx/html/                 #更换容器中的主目录          name: test  volumeClaimTemplates:  - metadata:      name: test      annotations:  #这是指定storageclass        volume.beta.kubernetes.io/storage-class: stateful-nfs    spec:      accessModes:        - ReadWriteOnce      resources:        requests:          storage: 100Mi[root@master ~]# kubectl apply -f statefulset.yaml [root@master ~]# kubectl get pod -o wideNAME                                      READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATESnfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          35m     10.244.2.2   node02              statefulset-test-0                        1/1     Running   0          21m     10.244.2.4   node02              statefulset-test-1                        1/1     Running   0          20m     10.244.1.4   node01              statefulset-test-2                        1/1     Running   0          3m52s   10.244.1.9   node01              statefulset-test-3                        1/1     Running   0          4m54s   10.244.2.5   node02              statefulset-test-4                        1/1     Running   0          4m43s   10.244.1.6   node01              statefulset-test-5                        1/1     Running   0          4m31s   10.244.2.6   node02              statefulset-test-6                        1/1     Running   0          4m25s   10.244.1.7   node01              statefulset-test-7                        1/1     Running   0          4m19s   10.244.2.7   node02              statefulset-test-8                        1/1     Running   0          4m12s   10.244.1.8   node01              statefulset-test-9                        1/1     Running   0          4m3s    10.244.2.8   node02              [root@master ~]# ls /nfsdata/ | wc -l10[root@master ~]# curl -I 10.244.2.4HTTP/1.1 200 OKDate: Wed, 12 Feb 2020 10:05:34 GMTServer: Apache/2.4.41 (Unix)Last-Modified: Wed, 12 Feb 2020 09:45:37 GMTETag: "c-59e5dd5ac0a63"Accept-Ranges: bytesContent-Length: 12Content-Type: text/html[root@master ~]# curl -I 10.244.2.8HTTP/1.1 403 ForbiddenServer: nginx/1.17.8Date: Wed, 12 Feb 2020 10:05:41 GMTContent-Type: text/htmlContent-Length: 153Connection: keep-alive

由此可以看出在执行扩容操作时,并不会更改pod,这就是StatefulSet的特点!

------------本文到此结束,感谢阅读------------

0