排版好像没有颜色和加粗等格式了,这个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。
架构图示
根据需求,可以得到下面的架构图:
分析:
- Pod通过StorageClass动态申请资源,可以参考第21篇文章,详细说明了操作流程,我们首先要把它部署好
- 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 