K8S上篇我们说了简单的配置以及临时存储
但是在实际生产中,如果有使用磁盘的需求,那么不太可能使用hostPath或者emptyDir,毕竟不是完全的持久化,在Pod死亡后也一同死亡了
这个时候,Volume的持久化就相当重要了
这种时候,对于持久化的卷,就可以考虑使用NFS GlusterFs 云厂商提供的块存储
那么我们先拿如何挂载NFS来看
对于NFS在宿主机的安装,我们稍微一说
# 在任意机器
yum install -y nfs-utils # 执行以下命令,启动 nfs 服务;创建共享目录 mkdir -p /nfs/data #执行命令 vi /etc/exports,创建 exports 文件,文件内容如下: echo “/nfs/data/ *(insecure,rw,sync,no_root_squash)” > /etc/exports #/nfs/data 172.26.248.0/20(rw,no_root_squash) systemctl enable rpcbind systemctl enable nfs-server systemctl start rpcbind systemctl start nfs-server exportfs -r #检查配置是否生效 exportfs # 输出结果如下所示 /nfs/data /nfs/data |
之后就创建了一个NFS的Server
如果是想使用这个NFS,可以考虑配置一个NFS的Client
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。
#安装客户端工具 yum install -y nfs-utils #执行以下命令检查 nfs 服务器端是否有设置共享目录 # showmount -e $(nfs服务器的IP) showmount -e 172.26.165.243 # 输出结果如下所示 Export list for 172.26.165.243 /nfs/data * #执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount mkdir /root/nfsmount # mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount #高可用备份的方式 mount -t nfs 172.26.165.243:/nfs/data /root/nfsmount # 写入一个测试文件 echo “hello nfs server” > /root/nfsmount/test.txt #在 nfs 服务器上执行以下命令,验证文件写入成功 cat /root/nfsmount/test.txt |
然后是在K8S上关于NFS的挂载使用
一个Pod的yaml如下
#测试Pod直接挂载NFS了
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs
namespace: default
spec:
containers:
– name: myapp
image: nginx
volumeMounts:
– name: html
mountPath: /usr/share/nginx/html/
volumes:
– name: html
nfs:
path: /nfs/data #1000G
server: 自己的nfs服务器地址
需要注意,需要在集群上每一台服务器都安装nfs-client,从而可以mount对应的远端nfs存储到本地
其次是我们在其中的volumes声明了挂载的nfs路径,这个路径要求必须要在nfs文件夹下创建好了
比如
Nfs:
Path: ./nfs/data/nginx
这个nginx文件夹就需要创建好
从上面的nfs-client和nfs path中,就暴露了直接挂载的缺点,需要的准备工作不少
那么为了消除这个弱点,K8S提供了PV PVC StorageClass
PV是PersistentVolume 持久卷
集群中的一块存储,记录了存储背后的实现细节
PVC PersistentVolumeClain PVC
是Pod等对象对存储的请求
规定了请求的大小和请求的模式,诸如ReadWriteOnce ReadOnlyMany
StorageClass 存储累
将不同的PVC抽象成一个对象,更加抽象PVC和PV
我们将上面的手动挂载流程,套用到PV – PVC -StorageClass这个模板
首先我们创建一个PV,并且声明StorageClass
apiVersion: v1
kind: PersistentVolume metadata: name: pv-volume-10m labels: type: local spec: storageClassName: my-nfs-storage capacity: storage: 100m accessModes: – ReadWriteOnce nfs: ## 使用nfs存储系统 server: 10.170.11.8 ## 没type path: /nfs/data/haha ### abc文件夹提前创建 |
这样就会创建一个容量为100mb,模式为可读写,使用nfs,storageClass为my-nfs-storage的PV
其次是声明一个PVC绑定这个pv
并且寻一个Pod去使用这个PVC
—
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
namespace: default
labels:
app: nginx-pvc
spec:
storageClassName: my-nfs-storage ## 存储类的名字
accessModes:
– ReadWriteOnce
resources:
requests:
storage: 50m
声明了一个PVC的请求,要求的storageClassName必须要和PV一致
这样K8S就会在storageClass中挑选最为合适的进行绑定
之后的Pod书写中加上一个volumes为PVC类型的和下面的PVC名称一致即可使用了
apiVersion: v1
kind: Pod metadata: name: “nginx-pvc” namespace: default labels: app: “nginx-pvc” spec: containers: – name: nginx-pvc image: “nginx” ports: – containerPort: 80 name: http volumeMounts: – name: localtime mountPath: /etc/localtime – name: html mountPath: /usr/share/nginx/html volumes: – name: localtime hostPath: path: /usr/share/zoneinfo/Asia/Shanghai – name: html persistentVolumeClaim: claimName: nginx-pvc ### 你的申请书的名字 restartPolicy: Always |
官方文档连接为:
https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
其次是关于PV和PVC中一些原生的配置项
分别关于了回收的策略和访问模式
在之前,我们可以在get pv的时候看到pv的状态栏中有一个RECLAIM POLICY
默认是Retain
这个设置表示的手动回收
其次的状态还有一个Status,在没有和PVC进行绑定之前,状态是Available
绑定之后就是Bound
在删除PVC之后,如果回收的策略是Retain,则不会删除这个PV,而是将PV的Status标记为Release
并且将PV中的数据保存
其次,如果标记为Recycle,那么就是删除PV内部的数据,再次变为可用
还有一个是Delete,就是在删除PVC的时候,PV一同删除
对于不同的PV实现,支持的也不同
目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。
典型测试的Yaml如下:
apiVersion: v1
kind: PersistentVolumeClaim metadata: name: pv-12-recycle namespace: default labels: app: pv-12-recycle spec: storageClassName: my-nfs-storage ### pv分组 accessModes: – ReadWriteOnce resources: requests: storage: 12m |
apiVersion: v1
kind: PersistentVolume metadata: name: pv-volume-12m-recycle labels: type: local spec: persistentVolumeReclaimPolicy: Recycle ## 回收 storageClassName: my-nfs-storage capacity: storage: 12m accessModes: – ReadWriteOnce nfs: ## 使用nfs存储系统 server: 10.170.11.8 ## 没type path: /nfs/data/recycle ### abc文件夹提前创建 |
我们将回收的策略persistentVolumeReclaimPolicy标记为了Recycle
如果将绑定的PVC删除后,这个PV会从Bound状态变为Available
而如果标记Retain,那么则是显示为Release,表示之前和哪个PVC绑定,方便管理员去手动的进行释放,如果想要复用,可以考虑创建新的PV卷
Status的状态有
Released pv释放,释放了和PVC的关联,但其他的PVC并不能重新绑定上来
Available pv可用,可以和任意的pvc进行绑定
Bound 已经绑定
Failed 卷的自动回收操作失败了
然后是访问模式
https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#access-modes
分为了
ReadWriteOnce 供一个节点进行读写挂载
ReadOnlyMany 供多个节点只读挂载
ReadWriteMany 供多个节点进行读写瓜子啊
ReadWriteOncePod 供一个Pod以读写进行挂载
还有这一些缩写形式
RWO – ReadWriteOnce
ROX – ReadOnlyMany
RWX – ReadWriteMany
RWOP – ReadWriteOncePod
官方文档上还有这不同的type的Volume对于读写模式的支持
最后是关于PV中的动态供应
因为从上面的PV和PVC的书写方式来看
需要运维人员提前创建好不同的PV,由K8S进行负责绑定
这样的处理相当繁杂,不可能有一万个PVC就要手动创建一万个PV
于是K8S提供了动态供应
上面的中我们假设有HDD SDD等存储阵列
而一个PVC被创建出来了,根据填充的storageClass字段
来选择对应的storageClass进行匹配,而选择的StorageClass则是根据内部配置的供应商去动态的创建PV
详细的架构图如下
开发人员创建PVC,选择对应StorageClass,StorageClass由集群管理员创建
内部有不同的供应商,来根据PVC来创建PV,并进行绑定
那么这个StorageClass的提供者是其中的一个字段
StorageClass的provisioner
我们看NFS提供的Provisioner如何书写
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
这里面表示我们需要部署一个Deployment去管理提供商Pod
然后是对应的RBAC权限分配
apiVersion: apps/v1
kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: – name: nfs-client-provisioner image: gcr/nfs-subdir-external-provisioner:v4.0.2 # resources: # limits: # cpu: 10m # requests: # cpu: 10m volumeMounts: – name: nfs-client-root mountPath: /persistentvolumes env: – name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner – name: NFS_SERVER value: 10.170.11.8 ## 指定自己nfs服务器地址 – name: NFS_PATH value: /nfs/data ## nfs服务器共享的目录 volumes: – name: nfs-client-root nfs: server: 10.170.11.8 path: /nfs/data — |
RBAC就暂时不贴上来了
需要注意的是,上面的image是很可能拉不下来的,需要注意换成私有源或者国内的源
下面的ENV中我们配置了相关的NFS-Server配置
Volumes中也配置了nfs的配置
然后需要配置一个StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass metadata: name: managed-nfs-storage annotations: storageclass.kubernetes.io/is-default-class: “true” provisioner: k8s-sigs.io/nfs-subdir-external-provisioner #provisioner指定一个供应商的名字。 #必须匹配 k8s-deployment 的 env PROVISIONER_NAME的值 parameters: archiveOnDelete: “true” ## 删除pv的时候,pv的内容是否要备份 #### 这里可以调整供应商能力。 |
需要注意,上面的provisioner中的值是要和provisioner中的对应ENV一致的
其次是annotaions中我们加上了注解storageclass.kubernetes.io/is-default-class: “true”
表示这个StorageClass是默认的Class
之后就可以申请PVC进行使用了
提供商会自动创建一个PV给PVC使用
默认的回收策略是delete
如果需要配置其他的回收策略,比如当其中有文件的时候进行备份,则可以进行设置日其他
apiVersion: storage.k8s.io/v1
kind: StorageClass metadata: name: nfs-client provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment’s env PROVISIONER_NAME’ parameters: pathPattern: “${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}” # waits for nfs.io/storage-path annotation, if not specified will accept as empty string. onDelete: delete |