在容器的生命周期里,位于磁盘上的文件,它的生命周期是很短暂的,docker里面如此,kubernetes里亦然。
数据很可能因为各种不可抗因素丢失,比如pod被迫下线时,它会根据rs控制器的数量定义,重新生成一个干净状态的新pod。
Volume的引入不但解决里数据稳定性的问题,也解决了同一个pod内,多个containers数据共享的需求;
和docker里不同的是:
1)kubernetes中内置封装了很多存储类型,pod也可以选择性的使用一个或多个。
2)当pod被删除时,Volume才可能会被清理,并且数据是否丢失和删除取决于Volume的具体类型和其回收策略
kubernetes内置封装了很多存储类型,大致可分为以下七大部分:
我已经整理好了官方配置文档,大家可以直接按需阅读,如何使用和配置。
存储类型 | 存储组件 | 官网文档 |
---|---|---|
云存储 | awsElasticBlockStore | awsElasticBlockStore |
云存储 | azureDisk | azureDisk |
云存储 | azureFile | azureFile |
云存储 | gcePersistentDisk | gcePersistentDisk |
云存储 | vsphereVolume | vsphereVolume |
分布式存储 | cephfs | cephfs |
分布式存储 | glusterfs | glusterfs |
分布式存储 | rbd | rbd |
网络存储 | nfs | nfs |
网络存储 | fc | fc |
网络存储 | iscsi | iscsi |
临时存储 | emptyDir | emptyDir |
本地存储 | hostPath | hostPath |
特殊存储 | configMap | configMap |
特殊存储 | downwardAPI | downwardAPI |
特殊存储 | secret | secret |
自定义存储 | csi | csi |
持久卷申请 | persistentVolumeClaim | persistentVolumeClaim |
pv(持久卷)和pod资源一样,拥有生命周期,共分为以下四种:
Provisioning: 正在申明
Binding: 正在绑定
using: 正在使用
Reclaiming: 正在回收
当pod资源被删除时,其相关pv和数据如何操作?该删除还是保留呢?
kubernetes通过persistentVolumeReclaimPolicy字段进行设置:
Delete: 数据和pv都会删除
Recyle: (已废弃)
Retain: 数据和pv都不动
PV的申明类型可分为以下两种:
Static(静态):
管理员根据使用情况,人为预先进行配置
Dynamic(动态):
基于已创建的StorageClasses(简称SC)存储类,起到动态申请和创建的作用
API server需要增加一个参数配置:–enable-admission-plugins,具体类型参考:storage-classes
定义:
PVC:描述使用者(Pod)想要使用的持久化属性,比如存储大小、读写权限等
PV:描述一个具体的Volume属性,比如Volume的类型、挂载目录、远程存储服务器地址等
SC:运维人员根据pv特征,可能是性能、质量级别、备份策略等进行定义的抽象存储类,通过接收pvc请求,从而启到动态实例化pv的效果
你可能还有一点茫然,我来举个例子:
PVC:好比接口,使用者只需要知道这个接口如何使用即可,比如该传哪些参数,哪些是必传的等等,他并不需要了解接口是如何实现的
PV:就是这些接口的实现,内部是用nfs,还是ceph的存储系统等等
SC:则是这些接口根据一系列规则所进行的抽象类,通过接收pvc请求,从而启到动态实例化pv的效果
另外,还有2点是非常重要的:
1.pv没有namespace名称空间概念,而pvc有namespace名称空间的概念
2.pv和pvc一一对应绑定
#pv的API字段配置说明
[root@centos-1 mainfasts]# kubectl explain pods.spec.volumes
KIND: Pod
VERSION: v1
RESOURCE: volumes <[]Object>
#pvc的API字段配置说明
[root@centos-1 dingqishi]# kubectl explain pods.spec.volumes.persistentVolumeClaim
KIND: Pod
VERSION: v1
RESOURCE: persistentVolumeClaim
至此,本章节的知识点也已经全部讲完了,你是否已经明白了呢?
首先你要先准备好nfs的挂载配置,我这里的配置如下所示:
角色 | ip | 备注 |
---|---|---|
server | 192.168.0.11 | 共享目录:/home/nfstestdir |
client | 192.168.0.12 | 挂载点:/mnt |
1)首先编辑pv.yaml的配置文件,正确填写nfs服务端的配置信息,并使用apply -f命令生成
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 100Mi
accessModes:
- ReadWriteMany
nfs:
# FIXME: use the right IP
server: 192.168.0.11
path: "/home/nfstestdir"
注意:pv是没有名称空间概念的,要记住!!!
2)编辑pvc.yaml,需要指定刚才创建的pv的名字,并apply -f生成
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
namespace: pv-test
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 90Mi
3)此时你可以通过以下命令查看到pv和pvc的状态了,此时pv和pvc的绑定已经完成了
[root@k8s-etcd-mater01 aaron]# kubectl get pvc -n pv-test
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pvc Bound nfs-pv 100Mi RWX 17s
[root@k8s-etcd-mater01 aaron]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv 100Mi RWX Retain Bound pv-test/nfs-pvc 53s
4)接下来我们要部署一个pod,让他使用pvc资源
apiVersion: v1
kind: Pod
metadata:
name: nginx-volume-pvc
namespace: pv-test
spec:
containers:
- name: nginx-pvc
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: html-pvc #自定义名的引用
mountPath: /usr/share/nginx/html/
volumes: #这里是选择volume的类型
- name: html-pvc #自定义名
persistentVolumeClaim:
claimName: nfs-pvc #我们刚才定义的pvc名
注意:pvc是有名称空间的,需要使用pvc的话,需要和pvc在同一个名称空间里!
5)此时pvc的状态已经是Bound了,
[root@k8s-etcd-mater01 aaron]# kubectl get pod -n pv-test
NAME READY STATUS RESTARTS AGE
nginx-volume-pvc 1/1 Running 0 7m1s
[root@k8s-etcd-mater01 aaron]# kubectl get pvc -n pv-test
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pvc Bound nfs-pv 100Mi RWX 21m
[root@k8s-etcd-mater01 aaron]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv 100Mi RWX Retain Bound pv-test/nfs-pvc 22m
上面我们使用了基于nfs静态配置的方法,来给pod资源提供存储容量,这个方式的缺点显而易见。
需要我们作为管理员,预先配置好存储容量:要几个pv,并且容量多少!
这种协作方式一般不太可取,后面我将以NFS Provisioner为例,来讲述动态供给的例子。
1.NFS Provisioner介绍
NFS Provisioner是一个自动配置卷程序,它使用现有的和已配置的 NFS 服务器来支持通过持久卷声明动态配置Kubernetes持久卷。
你可以在Github-NFS Provisioner上找到他的项目。
2.NFS环境准备
这里我就沿用上面的环境了,不再另行配置
角色 | ip | 备注 |
---|---|---|
server | 192.168.0.11 | 共享目录:/home/nfstestdir |
client | 192.168.0.12 | 挂载点:/mnt |
3.部署方式
NFS Provisioner的部署方式可以分为两种:
helm和手工的方式。
1)helm的方式较为简单,命令如下:
如果你对helm还不熟悉却想使用这种部署方式,请先阅读Helm基础。
helm install stable/nfs-client-provisioner --set nfs.server=nfs_serverip --set nfs.path=nfs_server_path
2)手工方式:
本章将展示如何以手工方式部署安装。
4.创建SA
首先我们需要创建一个serviceaccount,并使用RoleBinding绑定到leader-locking-nfs-client-provisioner上面。
这里会有一些超纲,涉及RBAC策略,我们后面会讲~
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-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: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac.yaml
5.创建nfs-client
将nfs配置成storageclass,安装对应的自动配置程序nfs-client,可以自动创建持久卷(pv)。
每当创建storageclass时,就会在kubernetes里面自动创建pv,nfs目录下自动创建文件夹,省去手动创建的繁琐。
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.0.114 #nfs服务器
- name: NFS_PATH
value: /home/nfstestdir #共享目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.0.114 #nfs服务器
path: /home/nfstestdir #共享目录
kubectl apply -f nfs-client-deployment.yaml
6.创建存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs #---动态卷分配者名称,必须和上面创建的"provisioner"变量中设置的Name一致
parameters:
archiveOnDelete: "true" #---设置为"false"时删除PVC不会保留数据,"true"则保留数据
设置默认存储类(可选):
metadata.annotations:
storageclass.kubernetes.io/is-default-class: "true" #---设置为默认的storageclass
7.创建PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" #---需要与上面创建的storageclass的名称一致
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
8.测试
此时,我们要创建一个测试用的pod,将nfs存储挂载至容器的mnt目录,并新建一个success的文件,观察动态供给是否正常工作。
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim #我们定义的pvc
具体创建流程如下所示:
pod->test-claim(pvc)->managed-nfs-storage(SC存储类)->provisioner: fuseim.pri/ifs(PV:nfs-client)
此时,我们查看相关pv,发现已经动态供给了。
[root@k8s-etcd-mater01 nfs]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-50b542db-2ee3-11ea-a207-001c425c73bc 1Mi RWX Delete Bound default/test-claim managed-nfs-storage 41m
persistentvolume/pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd 2Gi RWO Delete Bound default/test-web-0 managed-nfs-storage 42m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/test-claim Bound pvc-50b542db-2ee3-11ea-a207-001c425c73bc 1Mi RWX managed-nfs-storage 41m
persistentvolumeclaim/test-web-0 Bound pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd 2Gi RWO managed-nfs-storage 61m
你也可以到nfs服务器端,查看success文件是否生成。
[root@k8s-node01 nfstestdir]# tree
.
├── 11
├── 12
├── 21313
├── 3
├── default-test-claim-pvc-50b542db-2ee3-11ea-a207-001c425c73bc
│ └── SUCCESS #看我看我
└── default-test-web-0-pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd
至此,基于nfs的动态Provisioner供给功能已经演示完毕,你要做的就是根据自己需求选取你所需的volume分类。
在本文第二节,我已经罗列了所有的存储类型官方文档,方便你直接查阅~