容器内部的磁盘文件是较为脆弱的,生产中往往由于某些不可抗因素,如pod被迫下限kubelet重新生产干净的pod导致原容器的重要文件被删除,或者容器被重新调度后,在新的宿主机找不到原来的文件等等问题,因此kubernetes根据不同情况提供了不同的持久卷来满足我们的需求。
参考blog:
https://www.cnblogs.com/xzkzzz/p/9633308.html
kubernetes内置了很多存储类型,用户可以通过 kubectl explain pods.spec.volumes
来查看支持的存储卷
hostPath 主机目录
emptyDir 空目录(pod销毁也随之销毁)
rbd 分布式存储之ceph块存储
local 卷表示挂载的本地存储设备,如磁盘、分区或目录
cephfs 分布式存储之cephfs
awsElasticBlockStore aws云存储
azureDisk azure云存储
azureFile azure云存储
glusterfs 分布式存储之glusterfs
downwardAPI 卷用于使向下 API 数据(downward API data)对应用程序可用。它挂载一个目录,并将请求的数据写入纯文本文件。
cinder OpenStack 块存储
configMap 配置中心
fc 卷允许将现有的 fc 卷挂载到 pod 中。您可以使用卷配置中的 targetWWN 参数指定单个或多个目标全球通用名称(World Wide Name)。如果指定了多个 WWN,则 targetWWN 期望这些 WWN 来自多路径连接。
flexVolume 抽象的存储服务,存储服务的管理软件
flocker 是一款开源的集群容器数据卷管理器。它提供了由各种存储后端支持的数据卷的管理和编排。
gcePersistentDisk 谷歌云上
gitRepo 卷是一个可以演示卷插件功能的示例。它会挂载一个空目录并将 git 存储库克隆到您的容器中。
iscsi iscsi 卷允许将现有的 iSCSI卷挂载到容器中。不像 emptyDir,删除 Pod 时 iscsi 卷的内容将被保留,卷仅仅是被卸载。这意味着 iscsi 卷可以预先填充数据,并且这些数据可以在 pod 之间“切换”。
nfs nfs Nas存储
persistentVolumeClaim 卷用于将 PersistentVolume 挂载到容器中。PersistentVolumes 是在用户不知道特定云环境的细节的情况下“声明”持久化存储(例如 GCE PersistentDisk 或 iSCSI 卷)的一种方式。
photonPersistentDisk
portworxVolume 是一个与 Kubernetes 一起,以超融合模式运行的弹性块存储层
projected 卷将几个现有的卷源映射到同一个目录中
quobyte 卷允许将现有的 Quobyte 卷挂载到容器中。
scaleIO ScaleIO 是一个基于软件的存储平台,可以使用现有的硬件来创建可扩展的共享块网络存储集群
secret 加密文件
storageos 动态存储
vsphereVolume 配置了 vSphere Cloud Provider 的 Kubernetes
pod可以选择一个或多个不同类型的存储进行进行挂载,与docker不同的是只有当pod被删除时,volume才会被清理,并且数据的删除取决于Volume的具体类型和回收策略。
用户可以通过 kubectl explain pod.spec.containers.volumeMounts
查看系统支持的挂载类型
查看说明:kubectl explain pod.spec.volumes.emptyDir
emptyDir的生命周期和pod生命周期相同,pod被删除对应的emptyDir也会被清理。
示例:同一个pod中的两个容器挂载同一个目录
apiVersion: v1
kind: Pod
metadata:
name: emptydir-demo
namespace: default
labels:
name: emptydir-demo
spec:
containers:
- name: emptydir-demo
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: emptydir-v
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox
imagePullPolicy: IfNotPresent
volumeMounts:
- name: emptydir-v
mountPath: /data/
command:
- "/bin/sh"
- "-c"
- "while true; do echo $(date) >> /data/index.html; sleep 2; done"
volumes:
- name: emptydir-v
emptyDir: {}
查看这个pod并访问nginx主页
kubectl describe pod emptydir-demo
curl 10.212.0.45
查看说明:kubectl explain pod.spec.volumes.hostPath
apiVersion: v1
kind: Pod
metadata:
name: host-dir-demo
namespace: default
labels:
name: host-dir-demo
spec:
containers:
- name: host-dir-demo
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: host-dir
mountPath: /usr/share/nginx/html/
volumes:
- name: host-dir
hostPath:
path: /data/pod/nginx
type: DirectoryOrCreate
我们现在尝试一下使用subPath仅仅挂载html目录
apiVersion: v1
kind: Pod
metadata:
name: host-dir-demo
namespace: default
labels:
name: host-dir-demo
spec:
containers:
- name: host-dir-demo
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: host-dir
mountPath: /usr/share/nginx/html/
subPath: html
volumes:
- name: host-dir
hostPath:
path: /data/pod/nginx
type: DirectoryOrCreate
查看一下宿主机的目录结构
[abc@abc nginx]# tree
.
├── html
└── index.html
1 directory, 1 file
可以看到在原来的宿主机目录下单独生成了新的挂载目录
查看说明: kubectl explain pod.spec.volumes.nfs
安装NFS服务
yum install nfs-utils rpcbind -y
#nfs-utils:NFS主程序,rpcbind:PRC主程序,客户端和服务器都必须安装。
#启动RPC bind服务
systemctl start rpcbind
#服务端修改配置文件
/opt/nfs/data1 192.168.163.0/24(rw,no_root_squash) client-A.ctos.zu(rw,sync)
#[共享目录] [客户端地址1(权限)] [客户端地址2(权限)]
#检查一下配置文件
exportfs -rv
#启动NFS服务
systemctl start nfs
启动nginx容器挂载NFS目录
apiVersion: v1
kind: Pod
metadata:
name: nfs-dir-demo
namespace: default
labels:
name: nfs-dir-demo
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nfs-dir
mountPath: /usr/share/nginx/html/
volumes:
- name: nfs-dir
nfs:
server: 192.168.163.252
path: /opt/nfs/data1
PersistentVolume 是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是 Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统。
查询方式: kubectl explain pv.spec
PV的API字段说明 kubectl explain pods.spec.volumes
PVC的API字段说明 kubectl explain pods.spec.volumes.persistentVolumeClaim
SC的字段说明 kubectl explain sc
定义一个基于NFS格式的PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-1
labels:
name: pv-nfs-1
spec:
nfs:
path: /opt/nfs/data1
server: 192.168.163.252
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi
查看PV资源
kubectl get pv
查看说明:kubectl explain pvc.spec
ersistentVolumeClaim 是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)。
虽然 PersistentVolumeClaims 允许用户使用抽象存储资源,但用户需要具有不同性质(例如性能)的 PersistentVolume 来解决不同的问题。集群管理员需要能够提供各种各样的 PersistentVolume,这些PersistentVolume 的大小和访问模式可以各有不同,但不需要向用户公开实现这些卷的细节。对于这些需求,StorageClass 资源可以实现。
创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs-1
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 1.5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pod-pvc-1
namespace: default
labels:
name: pod-pvc-1
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: pv-nfs
mountPath: /usr/share/nginx/html/
volumes:
- name: pv-nfs
persistentVolumeClaim:
claimName: pvc-nfs-1
前面的 PV 都是静态的,所以导致当我要使用的一个 PVC 的话就必须手动去创建一个 PV,当pvc申请的时候不一定有满足pvc要求的pv,那怎么办呢?kubernetes为 为管理员提供了描述存储 “class(类)” 的方法(StorageClass)
要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner,这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
自动创建的 PV 以${namespace}-${pvcName}-${pvName}这样的命名格式创建在 NFS 服务器上的共享数据目录中
而当这个 PV 被回收后会以archieved-${namespace}-${pvcName}-${pvName}这样的命名格式存在 NFS 服务器上。
创建对应的SA并绑定
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
新建的一个名为 nfs-client-provisioner 的ServiceAccount,然后绑定了一个名为 nfs-client-provisioner-runner 的ClusterRole,而该ClusterRole声明了一些权限,其中就包括对persistentvolumes的增、删、改、查等权限,所以我们可以利用该ServiceAccount来自动创建 PV。
创建NFS-CLINET帮助我们动态创建PV资源
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
spec:
selector:
matchLabels:
app: nfs-client-provisioner
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.163.252 #nfs服务器
- name: NFS_PATH
value: /opt/nfs/data2 #共享目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.163.252 #nfs服务器
path: /opt/nfs/data2 #共享目录
将nfs配置成storageclass
,安装对应的自动配置程序nfs-client
,可以自动创建持久卷(pv)。
每当创建storageclass
时,就会在kubernetes
里面自动创建pv
,nfs
目录下自动创建文件夹,省去手动创建的繁琐。
创建存储类:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs #---动态卷分配者名称,必须和上面创建的"provisioner"变量中设置的Name一致
parameters:
archiveOnDelete: "true" #---设置为"false"时删除PVC不会保留数据,"true"则保留数据
查看一下刚才创建的SC
kubectl get sc
创建一个基于SC的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: 200Mi
启动一个pod绑定我们刚才创建的PVC
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
查看创建的PV和PVC
kubectl get pv,pvc