Kubernetes针对有状态服务数据持久化之StatefulSet(自动创建PVC)

一、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存储了!

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

2)创建rbac授权

[[email protected] ~]# vim rbac-rolebind.yaml
apiVersion: v1                            #创建一个用于认证的服务账号
kind: ServiceAccount
metadata:
  name: nfs-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1        #创建群集规则
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
rules:
   -  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/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: default                    #必写字段,否则会提示错误
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
[[email protected] ~]# kubectl apply -f rbac-rolebind.yaml    

3)创建nfs-deployment.资源

[[email protected] ~]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  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
[[email protected] ~]# kubectl apply -f nfs-deployment.yaml
[[email protected] ~]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          2m34s

4)创建SC(Storage Class)

[[email protected] ~]# vim sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: stateful-nfs
  namespace: xiaojiang-test
provisioner: lzj                  #这个要和nfs-client-provisioner的env环境变量中的PROVISIONER_NAME的value值对应。
reclaimPolicy: Retain               #指定回收策略为Retain(手动释放)
[[email protected] ~]# kubectl apply -f sc.yaml
[[email protected] ~]# kubectl get StorageClass
NAME           PROVISIONER   AGE
stateful-nfs   lzj           17s

5)创建Pod

[[email protected] ~]# vim statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc                    #从名称就可以是无头服务
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
    name: myweb
  selector:
    app: headless-pod
  clusterIP: None                        #不分配群集的IP地址,所以不具备负载均衡的能力
---
apiVersion: apps/v1
kind: StatefulSet                          #定义pod中运行的应用
metadata:
  name: statefulset-test
spec:
  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
[[email protected] ~]# kubectl apply -f statefulset.yaml
[[email protected] ~]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          10m
statefulset-test-0                        1/1     Running   0          29s
statefulset-test-1                        1/1     Running   0          18s
statefulset-test-2                        1/1     Running   0          11s
[[email protected] ~]# kubectl get pv
[[email protected] ~]# kubectl get pvc              #PV与PVC已经生成
[[email protected] ~]# ls /nfsdata/
default-test-statefulset-test-0-pvc-54d0b06c-698e-4f1a-8327-255b10978cbe
default-test-statefulset-test-1-pvc-1b499d49-a787-4f2b-b238-404b05f75fd7
default-test-statefulset-test-2-pvc-7766f8da-6f3b-4c1f-9eb8-dfadda1e656f
[[email protected] ~]# echo "hello world" > /nfsdata/default-test-statefulset-test-0-pvc-54d0b06c-698e-4f1a-8327-255b10978cbe/index.html
[[email protected] ~]# kubectl get pod -o wide | grep test-0
statefulset-test-0                        1/1     Running   0          4m53s   10.244.2.4   node02   <none>           <none>
[[email protected] ~]# curl 10.244.2.4
hello world
[[email protected] ~]# curl -I 10.244.2.4
HTTP/1.1 200 OK
Date: Wed, 12 Feb 2020 09:52:04 GMT
Server: Apache/2.4.41 (Unix)
Last-Modified: Wed, 12 Feb 2020 09:45:37 GMT
ETag: "c-59e5dd5ac0a63"
Accept-Ranges: bytes
Content-Length: 12
Content-Type: text/html
#可以看出现在提供web页面的服务是Apache

6)对pod进行更新并扩容

[[email protected] ~]# vim statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
    name: myweb
  selector:
    app: headless-pod
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-test
spec:
  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
[[email protected] ~]# kubectl apply -f statefulset.yaml
[[email protected] ~]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
nfs-client-provisioner-66df958f9c-mbvhv   1/1     Running   0          35m     10.244.2.2   node02   <none>           <none>
statefulset-test-0                        1/1     Running   0          21m     10.244.2.4   node02   <none>           <none>
statefulset-test-1                        1/1     Running   0          20m     10.244.1.4   node01   <none>           <none>
statefulset-test-2                        1/1     Running   0          3m52s   10.244.1.9   node01   <none>           <none>
statefulset-test-3                        1/1     Running   0          4m54s   10.244.2.5   node02   <none>           <none>
statefulset-test-4                        1/1     Running   0          4m43s   10.244.1.6   node01   <none>           <none>
statefulset-test-5                        1/1     Running   0          4m31s   10.244.2.6   node02   <none>           <none>
statefulset-test-6                        1/1     Running   0          4m25s   10.244.1.7   node01   <none>           <none>
statefulset-test-7                        1/1     Running   0          4m19s   10.244.2.7   node02   <none>           <none>
statefulset-test-8                        1/1     Running   0          4m12s   10.244.1.8   node01   <none>           <none>
statefulset-test-9                        1/1     Running   0          4m3s    10.244.2.8   node02   <none>           <none>
[[email protected] ~]# ls /nfsdata/ | wc -l
10
[[email protected] ~]# curl -I 10.244.2.4
HTTP/1.1 200 OK
Date: Wed, 12 Feb 2020 10:05:34 GMT
Server: Apache/2.4.41 (Unix)
Last-Modified: Wed, 12 Feb 2020 09:45:37 GMT
ETag: "c-59e5dd5ac0a63"
Accept-Ranges: bytes
Content-Length: 12
Content-Type: text/html
[[email protected] ~]# curl -I 10.244.2.8
HTTP/1.1 403 Forbidden
Server: nginx/1.17.8
Date: Wed, 12 Feb 2020 10:05:41 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

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

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

原文地址:https://blog.51cto.com/14157628/2470677

时间: 2024-10-04 12:46:42

Kubernetes针对有状态服务数据持久化之StatefulSet(自动创建PVC)的相关文章

k8s数据持久化之statefulset的数据持久化,并自动创建PV与PVC

一:Statefulset StatefulSet是为了解决有状态服务的问题,对应的Deployment和ReplicaSet是为了无状态服务而设计,其应用场景包括:1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现2.稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现3.有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依

k8s的StatefulSet(有状态服务)实现

StatefulSet介绍 遇到的问题: 使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个来保证可用性,但是由于是无状态的,Pod挂了的时候与之前的Volume的关系就已经断开了,新起来的Pod无法找到之前的Pod.但是对于用户而言,他们对底层的Pod挂了没有感知,但是当Pod挂了之后就无法再使用之前挂载的磁盘了. StatefulSet: 是一种给Pod提供唯一标志的控制器,它可以保证部署和扩展

Kubernetes数据持久化方案

在开始介绍k8s持久化存储前,我们有必要了解一下k8s的emptydir和hostpath.configmap以及secret的机制和用途. 1.EmptydirEmptyDir是一个空目录,他的生命周期和所属的 Pod 是完全一致的,EmptyDir主要作用可以在同一 Pod 内的不同容器之间共享工作过程中产生的文件.如果Pod配置了emptyDir类型Volume, Pod 被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致

kubernetes的应用数据持久化

1.无状态应用与有状态应用 应用的有状态和无状态是根据应用是否有持久化保存数据的需求而言的,即持久化保存数据的应用为有状态的应用,反之则为无状态的应用.常见的系统往往是有状态的应用,比如对于微博和微信这类应用,所有用户发布的内容和留言都是要保存记录的.但是一个系统往往是由众多微服务或更小的应用模块构成的.有的微服务或模块其实并没有数据持久化的需求.例如,搭建一个Wordpress博客系统需要部署一个前端的PHP应用,以及一个后端的MySQL数据库.虽然整个博客系统有持久化的需求,是一个有状态的系

Kubernetes数据持久化之Storage Class(存储类)自动创PV

通过博文Kubernetes的存储之Volume可以了解到Kubernets实现数据持久化的流程为:搭建NFS底层存储-->创建PV-->创建PVC-->创建pod最终将pod中的container实现数据的持久化! 从上述流程中,看似没有什么问题,但是仔细研究就会发现:PVC在向PV申请存储空间时,是根据指定PV的名称.访问模式.容量大小来决定具体向哪个PV申请空间的. 打比方说:如果PV的容量是20G,定义的访问模式是WRO(只允许以读写的方式挂载到单个节点),而PVC申请的存储空间

Kubernetes数据持久化之Storage Class(存储类)及自动创建PV

通过博文Kubernetes的存储之Volume可以了解到Kubernets实现数据持久化的流程为:搭建NFS底层存储-->创建PV-->创建PVC-->创建pod最终将pod中的container实现数据的持久化! 从上述流程中,看似没有什么问题,但是仔细研究就会发现:PVC在向PV申请存储空间时,是根据指定PV的名称.访问模式.容量大小来决定具体向哪个PV申请空间的. 打比方说:如果PV的容量是20G,定义的访问模式是WRO(只允许以读写的方式挂载到单个节点),而PVC申请的存储空间

k8s存储数据持久化,emptyDir,hostPath,基于Nfs服务的PV,PVC

在docker和K8S中都存在容器是有生命周期的,因此数据卷可以实现数据持久化. 数据卷解决的主要问题: 1.数据持久性:当我们写入数据时,文件都是暂时性的存在,当容器崩溃后,host就会将这个容器杀死,然后重新从镜像创建容器,数据就会丢失. 2.数据共享:在同一个Pod中运行容器,会存在共享文件的需求. 数据卷的类型: 1.emptyDiremptyDir数据卷类似于docker数据持久化的docker manager volume,该数据卷初分配时,是一个空目录,同一个Pod中的容器可以对该

Kubernetes数据持久化之Secret与ConfigMap

ConfigMap和Secret是Kubernetes中两种特殊类型的存储卷,ConfigMap这种资源对象主要用于提供配置数据以定制程序行为,不过一些敏感的配置信息,比如像用户名.密码.密钥等通常都是由Secret这种资源对象来进行配置的,他们将相应的配置信息保存于对象中,而后在Pod资源上以存储卷的形式将其挂载并获取相应配置,以实现配置与镜像文件的解耦. 一.Secret资源对象 1) Secret概述 Secret资源对象存储数据的方式是以键值对的方式进行存储的,在Pod资源进行Secre

k8s实践(七):存储卷和数据持久化(Volumes and Persistent Storage)

环境说明: 主机名 操作系统版本 ip docker version kubelet version 配置 备注 master Centos 7.6.1810 172.27.9.131 Docker 18.09.6 V1.14.2 2C2G master主机 node01 Centos 7.6.1810 172.27.9.135 Docker 18.09.6 V1.14.2 2C2G node节点 node02 Centos 7.6.1810 172.27.9.136 Docker 18.09.