精通k8s(36)StatefulSet-有状态集合(1)

排版好像没有颜色和加粗等格式了,这个k8s系列写完看看有没有别的平台。

对本系列有兴趣的,可以在电脑端看。

StatefulSet的简单解释

statefulset带有状态,下面举一个简例,假如说有三个号0,1,2分别对应三个人,而且这三个号还同时绑定了三个房子,如下所示:

当1号丢失之后,我们就会发现缺了一个人,于是赶紧补一个新人上来,但是它的编号还是1,由于房子(资源)是和1(序号)绑定的,那么补上来的这个人依然可以使用这个房子,这就是statefulset的全部故事。

对应到容器上,我们创建三个Pod分别是0、1、2,如果1号Pod删除重建了,那么系统就会察觉到,赶紧补一个上来。它发现是1号缺了,就按照1号的规格造一个Pod。可以看出在StatefulSet模式下,每个Pod都被编了号,成了”正式工“。

无状态和有状态

对于普通的Pod,创建之后最大的特点就是名字有时是不确定的,比如whoami-xxxxxxx,那么会有什么问题呢?假设有一个Pod名为whoami-abc,它绑定了一个PV资源,里面写了很多数据,当重建的时候名字变成随机的whoami-cde了,那么它怎么还能找到原来的那些数据呢?或者说系统怎么能让这两者之间建立映射呢?按逻辑上来说,它应该要找到,不然那些数据全没了。

StatefulSet就是要解决这个问题,它的核心是序号,假如有三个副本,就生成0,1,2这样的序号,每个Pod绑定一个;当序号对应的Pod缺失时,就补充到对应的序号上。下面我们先通过一个简单的实例说明。

实验需求

需求:用whoami创建两个副本,然后通过StorageClass类动态创建两个PV并绑定。我动手删除第一个Pod,那么系统会自动新建一个,我的要求是这个Pod还能自动绑定原来的那个PV。

架构图示

根据需求,可以得到下面的架构图:

分析:

    1. Pod通过StorageClass动态申请资源,可以参考第21篇文章,详细说明了操作流程,我们首先要把它部署好
    2. statefulSet是通过PVC模板生成PVC的,这一点就是它的核心

就绪之后,部署下面的代码:

实验代码

#文件名:whoami-statefulset.yaml

cat << 'EOF' > whoami-statefulset.yaml

# 1. 无头Service(为StatefulSet提供固定网络标识)
apiVersion: v1
kind: Service
metadata:
  name: whoami-headless
  labels:
    app: whoami
spec:
  clusterIP: None  # 无头Service标志
  ports:
  - port: 80
    name: web
  selector:
    app: whoami

---
# 2. StatefulSet配置(管理whoami实例)
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: whoami
spec:
  serviceName: whoami-headless
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
      - name: whoami
        image: crpi-gj5arn39i861t1eu.cn-hangzhou.personal.cr.aliyuncs.com/dev-team-sz/whoami
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: data  # 挂载PVC存储
          mountPath: /data  # 容器内的挂载目录

  # 3. PVC模板(动态生成PVC)
  volumeClaimTemplates:
  - metadata:
      name: data  # PVC名称前缀
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs-dynamic"  #存储类名称
      resources:
        requests:
          storage: 1Gi  # 每个实例申请1GB存储
EOF

#部署
kubectl apply -f whoami-statefulset.yaml

模板PVC生成具体PVC

关键在于StatefulSet配置的PVC模板,我们指定了使用的StorageClass类,这个参数很重要,那么statefulSet就根据模板生成一个具体的PVC,只是在幕后操作我们看不到,但最终它是执行了,所以可以通过kubectl get pvc命令查看到。

生成的PVC名字 = <PVC模板名>-<statefulSet名字>-<Pod序号>,所以我们看到的是data-whoami-0、data-whoami-1...。

生成的Pod名字

statefulSet部署的Pod名字也是固定的,等于<statefulSet名字>-<Pod序号>,一般序号就是从0开始,所以我们看到Pod的名字为whoami-0、whoami-1...。

生成PV

PVC生成之后就部署了,这就和第21篇文章的流程一样了,storageClass模板有指定的NFS插件,于是插件赶紧的在NFS服务端创建了一个目录,然后又创建了一个PV和申请的PVC绑定。

Pod如何关联到PVC呢?

PV和PVC的流程弄清楚了,现在还剩一个问题,Pod怎么关联到PVC呢?

这个也是通过statefulSet来实现,它在创建Pod的时候就明确了Pod和哪个PVC绑在一起,如下所示:

可以看到,只要作为核心的序号确定,那么这个PVC也确定了,0号Pod就对应data-whoami-0。

完整的流程梳理

我们首先安装NFS服务端,部署k8s下的NFS插件,再部署一个StorageClass,这三件套可以保证底层干活的流程是通的。

当使用statefulSet部署Pod时,每个Pod的名字都是固定的,主要按序号0,1,2...进行编号。然后根据模板生成具体的PVC,依然是按着序号绑定,比如0号Pod绑定0号的PVC,依此类推。

PVC生成并部署之后,底层干活的插件就会生成目录,并且在集群中生成一个PV,让PV和PVC绑定,又由于Pod和PVC绑定,那么Pod就相当于和得到的PV绑定了,Pod赶紧让PV挂载到自己内部的目录,资源获取就完成了!

当某个Pod重建时,就是补上丢失的号,无论Pod怎样,号是不变的,那么Pod绑定的就还是原序号的PVC和PV。

当Pod删除时,PVC和PV还存活,这是很容易理解的,不然新创建的Pod到哪绑定原来的PV呢?所以动态生成的PVC和PV需要手动删除。

流程结束。

实验观察

第一步:进入whoami-0号Pod,然后写入一个文件

kubectl exec -it whoami -- sh

#写入文件
vim default-data-whoami-0
...

第二步:进入master节点(也就是NFS服务端所在节点)的
/nfs/dynamic/default-data-whoami-0-xxx目录下查看

cd /nfs/dynamic
...

可以看到有文件default-data-whoami-0,说明写入成功。

第三步:删除whoami-0

kubectl delete pod whoami-0

第四步:再次进入whoami查看

kubectl exec -it whoami-0 -- sh
cd /data

可以看到原来存储的default-data-whoami-0还在,验证成功!!

实验结束的清理工作

kubectl delete -f whoami-statefulset.yaml
rm -rf whoami-statefulset.yaml
原文链接:,转发请注明来源!