k8s的statefulset(有状态服务)实现(代码片段)

author author     2023-04-19     606

关键词:

StatefulSet介绍

遇到的问题:

使用Deployment创建的Pod是无状态的,当挂在Volume之后,如果该Pod挂了,Replication Controller会再run一个来保证可用性,但是由于是无状态的,Pod挂了的时候与之前的Volume的关系就已经断开了,新起来的Pod无法找到之前的Pod。但是对于用户而言,他们对底层的Pod挂了没有感知,但是当Pod挂了之后就无法再使用之前挂载的磁盘了。

StatefulSet: 是一种给Pod提供唯一标志的控制器,它可以保证部署和扩展的顺序。

Pod一致性:包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个node节点无关。

稳定的次序:对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的。

稳定的网络:Pod的hostname模式为(statefulset名称)- (序号)。

稳定的存储:通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本,不会删除相关的卷。

(1) RC、 RS、Deployment、DS。-----> 无状态服务

template(模板):根据模板 创建出来的Pod,它们J的状态都是一模一样的(除了名称,IP, 域名之外)

可以理解为:任何一个Pod, 都可以被删除,然后用新生成的Pod进行替换。

(2) 有状态的服务: 需要记录前一 次或者多次通信中的相关事件,以作为一下通信的分类标准。比如: mysql等数据库服务。(Pod的名称,不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。)

mysql:主从关系。

如果把之前无状态的服务比喻为牛、羊等牲畜,因为,这些到一定时候就可以”送出“。那么,有状态就比喻为:宠物,而宠物不像牲畜一样到达一定时候“送出”,人们往往会照顾宠物的一生。

(3) 每一个Pod---->对应一个PVC---->每一个PVC对应一个PV。

storageclass:自动创建PV

需要解决:自动创建PVC。

实现原理

与 ReplicaSet 和 Deployment 资源一样,StatefulSet 也使用控制器的方式实现,它主要由 StatefulSetController、StatefulSetControl 和 StatefulPodControl 三个组件协作来完成 StatefulSet 的管理,StatefulSetController 会同时从 PodInformer 和 ReplicaSetInformer 中接受增删改事件并将事件推送到队列中:
技术图片
控制器 StatefulSetController 会在 Run 方法中启动多个 Goroutine 协程,这些协程会从队列中获取待处理的 StatefulSet 资源进行同步,接下来我们会先介绍 Kubernetes 同步 StatefulSet 的过程。

1,例子

(1)创建一个statefulset的yaml文件

[root@master yaml]# vim statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
  selector:
    app: headless-pod
  clusterIP: None     #没有同一的ip
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-test
spec:
  serviceName: headless-svc
  replicas: 3
  selector:
    matchLabels:
      app: headless-pod
  template:
    metadata:
      labels:
        app: headless-pod
    spec:
      containers:
      - name: myhttpd
        image: httpd
        ports:
        - containerPort: 80

Deployment : Deploy+RS+随机字符串(Pod的名称。)没有顺序的,可
以没随意替代的。

1、headless-svc :无头服务。因为没有IP地址,所以它不具备负载均衡的功能了。因为statefulset要求Pod的名称是有顺序的,每一个Pod都不能被随意取代,也就是即使Pod重建之后,名称依然不变。为后端的每一个Pod去命名。

2、statefulSet:定义具体的应用

3、volumeClaimT emplates:自动创建PVC,为后端的Pod提供专有的存储。

执行一下

[root@master yaml]# kubectl apply -f statefulset.yaml 

查看一下

[root@master yaml]# kubectl get svc

技术图片

[root@master yaml]# kubectl get pod
//可看到这些pod是有顺序的

技术图片

一、创建StorageClass资源对象。

1、基于NFS服务,创建NFS服务。

下载nfs所需安装包

[root@node02 ~]# yum -y install nfs-utils  rpcbind

创建共享目录

[root@master ~]# mkdir /nfsdata

创建共享目录的权限

[root@master ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)

开启nfs和rpcbind

[root@master ~]# systemctl start nfs-server.service 
[root@master ~]# systemctl start rpcbind

测试一下

[root@master ~]# showmount -e

技术图片

2、创建rbac权限。

[root@master yaml]# 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: [""]
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

执行一下

[root@master yaml]# kubectl apply -f rbac-rolebind.yaml 

3、创建Deployment资源对象,用Pod代替 真正的NFS服务。

[root@master yaml]# vim nfs-deployment.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      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: bdqn
            - name: NFS_SERVER
              value: 192.168.1.21
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.21
            path: /nfsdata

执行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml 

查看一下

[root@master yaml]# kubectl get pod

技术图片

4、创建storageclass的yaml文件

[root@master yaml]# vim test-storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: stateful-nfs
provisioner: bdqn  #通过provisioner字段关联到上述Deploy
reclaimPolicy: Retain

执行一下

[root@master yaml]# kubectl apply -f test-storageclass.yaml

查看一下

[root@master yaml]# kubectl get sc

技术图片

二,解决自动创建pvc

1、创建statefulset的yaml文件

[root@master yaml]# 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:
  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: /mnt
          name: test
  volumeClaimTemplates:  #> 自动创建PVC,为后端的Pod提供专有的存储。**
  - metadata:
      name: test
      annotations:   #这是指定storageclass
        volume.beta.kubernetes.io/storage-class: stateful-nfs
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi

在此示例中:

  • 创建了一个名为 headless-svcService 对象,由 metadata: name 字段指示。该 Service 会定位一个名为 headless-svc 的应用,由 labels: app: headless-svcselector: app: headless-pod 指示。该 Service 会公开端口 80 并将其命名为 web。而且该 Service 会控制网域并将互联网流量路由到 StatefulSet 部署的容器化应用。
  • 使用三个副本 Pod (replicas: 3) 创建了一个名为 web 的 StatefulSet。
  • Pod 模板 (spec: template) 指示其 Pod 标记为 app: headless-pod
  • Pod 规范 (template: spec) 指示 StatefulSet 的 Pod 运行一个容器 myhttpd,该容器运行版本为 httpd 映像。容器映像由 Container Registry 管理。
  • Pod 规范使用由 Service 打开的 web 端口。
  • template: spec: volumeMounts 指定一个名为 testmountPathmountPath 是容器中应装载存储卷的路径。
  • StatefulSet 预配了一个具有 100mb 预配存储空间的 PersistentVolumeClaimtest

执行一下

[root@master yaml]# kubectl apply -f statefulset.yaml

查看一下

[root@master yaml]# kubectl get pod

技术图片

如果第一个pod出现了问题,后面的pod就不会生成。

[root@master yaml]# kubectl get statefulsets

技术图片

2、 验证一下数据存储

容器中创建文件

[root@master yaml]# kubectl exec -it statefulset-test-0 /bin/sh
# cd /mnt
# touch testfile
# exit

宿主机查看一下

[root@master yaml]# ls /nfsdata/default-test-statefulset-test-0-pvc-bf1ae1d0-f496-4d69-b33b-39e8aa0a6e8d/
testfile

三、小实验

以自己的名称创建一个名称空间,以下所有资源都运行在此空间中。用statefuset资源运行一个httpd web服务,要求3个Pod,但是每个Pod的主界面内容不一样,并且都要做专有的数据持久化,尝试删除其中一个Pod,查看新生成的Pod,总结对比与之前Deployment资源控制器控制的Pod有什么不同之处?

(一)创建StorageClass资源对象。

注意:nfs服务要开启

1、创建namespace的yaml文件

[root@master yaml]# vim namespace.yaml 
kind: Namespace
apiVersion: v1
metadata:
  name: xgp-lll    #namespave的名称

执行一下

[root@master yaml]# kubectl apply -f namespace.yaml 

查看一下

[root@master yaml]# kubectl get namespaces 

技术图片

2. 创建rbac权限。

[root@master yaml]# vim rbac-rolebind.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: xgp-lll
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
  namespace: xgp-lll
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: xgp-lll
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

执行一下

[root@master yaml]# kubectl apply -f rbac-rolebind.yaml

3、创建Deployment资源对象,用Pod代替 真正的NFS服务。

[root@master yaml]# vim nfs-deployment.yaml 

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: xgp-lll
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      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: xgp
            - name: NFS_SERVER
              value: 192.168.1.21
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.21
            path: /nfsdata

执行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml 

查看一下

[root@master yaml]# kubectl get pod  -n xgp-lll 

技术图片

4、创建storageclass的yaml文件

[root@master yaml]# vim test-storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: stateful-nfs
  namespace: xgp-lll
provisioner: xgp  #通过provisioner字段关联到上述Deploy
reclaimPolicy: Retain

执行一下

[root@master yaml]# kubectl apply -f test-storageclass.yaml

查看一下

[root@master yaml]# kubectl get sc -n  xgp-lll

技术图片

(二)解决自动创建pvc

1、创建statefulset的yaml文件

apiVersion: v1
kind: Service
metadata:
  name: headless-svc
  namespace: xgp-lll
  labels:
    app: headless-svc
spec:
  ports:
  - port: 80
    name: myweb
  selector:
    app: headless-pod
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: statefulset-test
  namespace: xgp-lll
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,为后端的Pod提供专有的>存储。**
  - metadata:
      name: test
      annotations:   #这是指定storageclass
        volume.beta.kubernetes.io/storage-class: stateful-nfs
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 100Mi

执行一下

[root@master yaml]# kubectl apply -f statefulset.yaml

查看一下

[root@master yaml]# kubectl get pod -n xgp-lll 

技术图片

2、 验证一下数据存储

容器中创建文件

第一个
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-0 /bin/bash 
root@statefulset-test-0:/usr/local/apache2# echo 123 > /usr/local/apache2/htdocs/index.html

第二个
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-1 /bin/bash 
root@statefulset-test-2:/usr/local/apache2# echo 456 > /usr/local/apache2/htdocs/index.html

第三个
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-2 /bin/bash 
root@statefulset-test-1:/usr/local/apache2# echo 789 > /usr/local/apache2/htdocs/index.html

宿主机查看一下

第一个
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-0-pvc-ccaa02df-4721-4453-a6ec-4f2c928221d7/index.html 
123

第二个
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-1-pvc-88e60a58-97ea-4986-91d5-a3a6e907deac/index.html 
456

第三个
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-2-pvc-4eb2bbe2-63d2-431a-ba3e-b7b8d7e068d3/index.html 
789

访问一下

技术图片

k8s控制器-statefulset

StatefulSet是为了管理有状态服务的问题而设计扩展:有状态服务?StatefulSet是有状态的集合,管理有状态的服务,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数... 查看详情

k8s中statefulset资源类型的深入理解

参考技术Astatefulset是为了解决有状态服务的问题,而产生的一种资源类型(deployment和replicaSets是解决无状态服务而设计的)。这里可能有人说,mysql是有状态服务吧,但我使用的是deploment资源类型,mysql的data数据通过pv的方式存... 查看详情

k8s实践(13)--有状态服务statefulset详解(代码片段)

...服务相关 k8s实践(12)--K8sservice服务详解最近项目搭建基于StatefulSet创建常驻pod的GPU虚机平台,项目接近尾声,在此顺便做了个总结,温故而知新,而不是走马观花,浅尝辄止懂些概念。一、k8s集群的服务分类在... 查看详情

k8s部署eureka集群

...自己注册到彼此,因此要做一些特殊改动。主要是用到了StatefulSet和headlessservice这两个k8s对象StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括稳定的持久化存储,即Pod重... 查看详情

k8s系列深入解析有状态服务(代码片段)

...1基本介绍2使用介绍2.1  HeadlessService2.2 PersistentVolume2.3 StatefulSet2.4 InitContainers 3问题4投票序言在你想要放弃的时候,想想是什么让你当初坚持走到了这里。Kubernetes(k8s)是一个容器编排平台,允许在容器中运行应用程序... 查看详情

k8s中的statefulset应用

使用statefulset的场景通常有以下特点:有状态服务。集群(多节点)部署。节点有主从(备)之分。集群通常是主节点先运行,从节点后续运行并加入集群,这里就用statefulset资源的有序部署的特性。节点之间数... 查看详情

k8s数据持久化之statefulset的数据持久化,并自动创建pv与pvc(代码片段)

一:StatefulsetStatefulSet是为了解决有状态服务的问题,对应的Deployment和ReplicaSet是为了无状态服务而设计,其应用场景包括:1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现2.稳定的网络标志... 查看详情

从零开始入门k8s|有状态应用编排-statefulset

...标识、发布顺序确定性等。针对这类问题Kubernetes提供了StatefulSet控制器,作为帮助有状态应用部署和在K8s环境落地的Workload。一、“有状态”需求我们之前讲到过Deployment作为一个应用编排管理工具,它为我们提供了哪些功能?如... 查看详情

k8s部署有状态服务zookeeper示例(代码片段)

我们先不考虑配置文件的前提下:apiVersion:apps/v1kind:StatefulSet#####固定hostname,有状态的服务使用这个statefalset有个问题,就是如果那个pod不是running状态,这个主机名是无法解析的,这样就构成了一个死循环,我sed替换主机名的时... 查看详情

k8s介绍系列---statefulset介绍

...oyment是处理无状态的服务,但对于有状态的应用,就需要statefulset来处理stateful不仅能管理pod对象,还能确保这些pod的顺序性和一致性会创建volumeClaimTemplates配置,包括持久卷persistentVolume和用于绑定持久卷和pod的persistVolumeClaim资... 查看详情

k8s部署zk集群(代码片段)

一、简介1.1、statefulset控制器简介statefulset控制器是有状态应用副本集;在k8s集群statefulset用于管理以下副本集:稳定且唯一的网络标识符稳定且持久的存储有序,平滑的部署和扩展有序,平滑的删除和终止有序的滚动更新statefuls... 查看详情

kubernetes实现redis-statefulset集群(代码片段)

Kubernetes通过statefulset部署rediscluster集群部署redis集群方式的选择StatefulsetService&depolyment对于redis,mysql这种有状态的服务,我们使用statefulset方式为首选.我们这边主要就是介绍statefulset这种方式ps:statefulset的设计原理模型:拓扑状态.... 查看详情

k8s-statefulset控制器

一、statefulset简介statefulset是用来管理有效状态应用的工作负载API对象,也是一种POD控制器,那为什么要放在PV/PVC之后再简介呢?这是因为statefulset是必须也有持久化数据,每个POD所对应的PV都是不一样的。相对于Deployment所创建的... 查看详情

kubernetes之statefulset详解(代码片段)

...它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解... 查看详情

如何进行k8s存储系统

在K8S运行的服务,从简单到复杂可以分成三类:无状态服务、普通有状态服务和有状态集群服务。下面分别来看K8S是如何运行这三类服务的。无状态服务,K8S使用RC(或更新的ReplicaSet)来保证一个服务的实例数量,如果说某个Pod... 查看详情

kubernetes——statefulset详解

...它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解... 查看详情

k8s-statefulset(代码片段)

1、StatefulSet介绍RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、Bmongo复制集,rediscluster,rabbit... 查看详情

k8s学习-statefulset(模板更新扩缩容删除等)(代码片段)

...概念模板实战创建扩缩容更新删除删除Pod删除sts参考概念StatefulSet是用来管理有状态应用的工作负载API对象,kubectl中可以简写为sts。sts每个Pod生成一个唯一的标识符sts_name-number,number从0开始。StatefulSet会关联卷(volume... 查看详情