


k8s之PV、PVC存储静态供给
注意:定义PV的时候一定不要指明命名空间。和namespace一样,PV也是集群级别的,属于集群,不属于命名空间。所有的命名空间都可以用。但是PVC是属于命名空间级别的。Pod,Service属于命名空间中,所以需要定义。
温馨提示:pvc声明的容量大于PV的容量的话是无法进行绑定的
持久化存储
Volume 共享存储原理:
Kubernetes为了能更好的支持有状态应用的数据存储问题,除了基本的HostPath和EmptyDir提供的数据持久化方案之外,还提供了PV,PVC和StorageClass资源对象来对存储进行管理。
Kubernetes对于有状态的容器应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者emptyDir临时存储卷,而且需要更加可靠的存储来保存应用产生的重要数据,以便容器应用在重建之后,仍然可以使用之前的数据。不过,存储资源和计算资源(CPU/内存)的管理方式完全不同。为了能够屏蔽底层存储实现的细节,让用户方便使用,同时能让管理员方便管理,Kubernetes从v1.0版本就引入了PersistentVolume和PersistentVolumeClain两个资源对象来实现对存储的管理子系统
PV全称是Persisten Volume (持久化卷):是对底层网络存储的抽象,将共享存储定义为一种“资源”,比如节点(Node)也是一种容器应用可以“消费”的资源。PV由管理员进行创建和配置,它与共享存储的具体实现直接相关,例如GlusterFs、iSCSI、RBD或GCE/AWS公有云提供的共享存储,通过插件式的机制完成与共享存储的对接,以供应用访问和使用
PVC全称是PersistentVolumeClaim (持久化卷声明):是用户对于存储资源的一个“申请”。就像Pod “消费” Node的资源是一样的,PVC会消费PV的资源。PVC可以申请特定的存储空间和访问模式。
使用PVC“申请”到一定的存储空间仍然不足以满足应用对于存储设备的各种需求。通常应用程序都会对存储设备的特性和性能有不同的要求,包括读写速度、并发性能、数据冗余
等更高的要求。
PV详解
Volume是定义在Pod上的,属于"计算资源"的一部分,而实际上"网络存储"是相对独立于"计算资源"而存在的一种实体资源
1、PV只是网络存储,不属于任何Node,但可以在每个Node上访问 2、PV并不是定义在Pod上,而是独立于Pod之外的定义
PV作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型
等关键信息的设置。
PV和PVC的生命周期

这里采用NFS作为后端存储进行测试。安装NFS网络文件系统可参考如下文章:NFS网络文件系统介绍及部署
创建一个测试PV:pv1.yaml
apiVersion: v1
kind: PersistentVolume #指定类型为PV
metadata:
name: pv0001 #设置PV名字
spec:
capacity: #存储能力,持久卷资源和容量的描述,存储大小是唯一可设置或请求的资源。
storage: 5Gi #设置存储空间大小
accessModes: # 访问模式
- ReadWriteMany #设置访问模式,读写权限,可以被多个节点挂载
persistentVolumeReclaimPolicy: Recycle #回收策略。类似rm -rf
storageClassName:slow #存储类别,速率快慢
nfs:
path: "/data/disk1" #设置挂载点
server: 192.168.2.201 #指定NFS地址
readOnly: false #是否为只读
字段解释:
metadata:name 设置PV的名称 spec:capacity:storage 设置存储空间大小 spec:accessModes 设置访问模式 storageClassName 存储类别 persistentVolumeReclaimPolicy 回收策略(Reclaim Policy) nfs NFS相关设置
Reclaim Policy (回收策略):
目前支持如下三种回收策略:
保留 (Retain) 保留数据,需要手工处理 回收空间 (Recycle) 简单清除文件的操作 (例如执行rm -rf /allenjol/* 命令) 删除 (Delete) 与PV相连的后端存储完成volume的删除操作 (如AWS EBS、GCE PD、Azure Disk、Openstack Cinder等设备的内部volume清理)
AccessModes(访问模式):
只要资源提供者支持,持久卷能够被用任何方式加载到主机上。每种存储都会有不同的能力,每个 PV 的访问模式也会被设置成为该卷所支持的特定模式。例如 NFS 能够支持多个读写客户端,但是某个 NFS PV 可能会在服务器上以只读方式使用。每个 PV 都有自己的一系列的访问模式,这些访问模式取决于 PV 的能力。
PV和PVC是一 一对应的关系。一旦某个PV被PVC占用了他就会显示Bounding状态。就不可能被其他pvc占用。但是PVC相当于存储卷,却可以被多个Pod访问。PVC是否能被多个Pod访问需要定义被访问的模式accessMOde。
三种访问模式:
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载 ReadOnlyMany(ROX):只读权限,可以被多个节点挂载 ReadWriteMany(RWX):读写权限,可以被多个节点挂载
以上三种访问模式NFS类型都支持。
温馨提示:一个卷不论支持多少种访问模式,同时只能以一种访问模式加载。例如一个 GCEPersistentDisk 既能支持 ReadWriteOnce ,也能支持 ReadOnlyMany。
PV常见状态:
Available(可用) :空闲状态 Bound(已绑定):已经绑定到某个PVC Released(已释放):对应的PVC已经删除,但资源还没有被集群收回 Failed(失败):PV自动回收失败
PVC例子
PersistentVolumeClaim (PVC)
是用户的一个请求。他跟 Pod 类似。Pod 消费 Node 的资源,PVC 消费 PV 的资源。Pod 能够申请特定的资源(CPU 和 内存);Claim 能够请求特定的尺寸和访问模式(例如可以加载一个读写,以及多个只读实例)
如果某个Pod想申请某种类型的PV,则需要定义一个PersistentVolumeClaim(PVC)
PVC作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。帮助文档可以通过命令行kubectl explain pvc来查看。
1. 创建PVC:pvc1.yaml
apiVersion: v1
kind: PersistentVolumeClaim # 指定类型为PVC
metadata:
name: myclaim
spec:
accessModes: # 主要定义卷所应该拥有的访问模式
- ReadWriteOnce # 设置访问模式为单节点读写权限
resources: # 定义卷应该拥有的最小资源
requests:
storage: 10Gi # 申请10Gi的存储空间。带i的是以1024来定义的。不带i的是以1000来定义的
2. 在Pod中引用PVC:pvctest.yaml
kind: Pod
apiVersion: v1
metadata:
name: pvctest-pod
spec:
containers:
- name: my-pvc-frontend
image: nginx:1.12
volumeMounts: #Volume配置
- mountPath: "/var/www/html" # 挂载到容器中的目录
name: pvctest-pod
volumes:
- name: pvctest-pod
persistentVolumeClaim:
claimName: myclaim #引用的名字一定要和上面创建的pvc名字相同
删除PVC
删除PVC之前必须先删除已经使用了该PVC的POD。
创建的顺序:NFS---PV---PVC---POD 删除的顺序:POD---PVC---PV
创建两个测试pv和两个pvc:
[root@k8s-master mainfests]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv1 1Gi RWO Recycle Bound default/pvc-nfs 90m
persistentvolume/pv2-nfs 2Gi RWO Recycle Bound default/pvc2-nfs 60m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc-nfs Bound pv1 1Gi RWO 77m
persistentvolumeclaim/pvc2-nfs Bound pv2-nfs 2Gi RWO
下面describe pvc 以后发现该PVC已经被nfs-pvc的pod挂载使用
[root@k8s-master mainfests]# kubectl describe pvc pvc2-nfs
Name: pvc2-nfs
Namespace: default
StorageClass:
Status: Bound
Volume: pv2-nfs
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"name":"pvc2-nfs","namespace":"default"},"spec":{"accessMod...
pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 2Gi
Access Modes: RWO
VolumeMode: Filesystem
Mounted By: nfs-pvc-5ffcf8c95-cxzg6
nfs-pvc-5ffcf8c95-ff9mk
nfs-pvc-5ffcf8c95-zptgt
Events: <none>
[root@k8s-master mainfests]# kubectl get po
NAME READY STATUS RESTARTS AGE
nfs-pvc-5ffcf8c95-cxzg6 1/1 Running 0 57m
nfs-pvc-5ffcf8c95-ff9mk 1/1 Running 0 57m
nfs-pvc-5ffcf8c95-zptgt 1/1 Running 0 57m
[root@k8s-master mainfests]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-pvc 3/3 3 3 58m
下面删除pvc2和pv2
# 删除deploy同时会发现pod已经被删除掉
[root@k8s-master mainfests]# kubectl delete deploy nfs-pvc
deployment.extensions "nfs-pvc" deleted
[root@k8s-master mainfests]# kubectl get po
No resources found.
# 接下来删除pvc2-nfs和pv2-nfs
[root@k8s-master mainfests]# kubectl delete pvc pvc2-nfs
persistentvolumeclaim "pvc2-nfs" deleted
[root@k8s-master mainfests]# kubectl delete pv pv2-nfs
persistentvolume "pv2-nfs" deleted
# 查看pv,pvc发现已经被成功删除
[root@k8s-master mainfests]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pv1 1Gi RWO Recycle Bound default/pvc-nfs 95m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/pvc-nfs Bound pv1 1Gi RWO 81m
贴出一个deployment测试使用PVC例子
vim nfs-pvc-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-pvc
spec:
replicas: 3
template:
metadata:
labels:
app: nfs-pvc
spec:
containers:
- name: nginx
image: nginx:1.12.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: pvc2-nfs
---
apiVersion: v1
kind: Service
metadata:
name: nfs-pvc
labels:
app: nfs-pvc
spec:
type: NodePort
ports:
- port: 80
targetPort: web
selector:
app: nfs-pvc
查看Pod和svc
[root@k8s-master storageclass]# kubectl get po,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/nfs-pvc-955c4c849-7hfwb 1/1 Running 0 4m54s 172.20.2.7 192.168.2.221 <none> <none>
pod/nfs-pvc-955c4c849-8wptd 1/1 Running 0 4m54s 172.20.1.6 192.168.2.220 <none> <none>
pod/nfs-pvc-955c4c849-lxg44 1/1 Running 0 4m54s 172.20.1.5 192.168.2.220 <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 153d <none>
service/nfs-pvc NodePort 10.68.76.60 <none> 80:27005/TCP 4m54s app=nfs-pvc
我们把容器目录/user/share/nginx/html和挂载到了pvc2-nfs这个 PVC 上面,这个 PVC 就是对应着我们上面的 nfs 的共享数据目录的,该目录下面还没有任何数据,所以现在直接通过node节点的ip:port访问是会出现403的情况。现在我们在/data/k8s这个目录下面新建一个 index.html 的文件。
echo "<h1>Hello Kubernetes~</h1>" >> /data/k8s/index.html
浏览器访问:192.168.2.220:27005

但是当前容器中的数据是直接放到共享数据目录根目录下面的,如果以后我们又有一个新的 nginx 容器也做了数据目录的挂载就会出现冲突的情况。这个时候就不太好区分了,这个时候我们可以在 Pod 中使用一个新的属性:subPath,该属性可以来解决这个问题,我们只需要更改上面的 Pod 的 YAML 文件即可:
...
volumeMounts:
- name: www
subPath: nginxpvc-test
mountPath: /usr/share/nginx/html
...
然后将刚才的index.html文件放到/data/k8s/nginxpvc-test/下这时候能正常访问到数据了
mv /data/k8s/index.html /data/k8s/nginxpvc-test/
# 更新更改过后的deployment文件
kubectl apply -f nfs-pvc-deploy.yaml
测试数据是否会丢失 删除deployment,这时候pod都会被删除,然后查看subpath目录下的数据是否存在。可以看到数据是存在的
[root@k8s-master storageclass]# kubectl delete deployment nfs-pvc
deployment.extensions "nfs-pvc" deleted
[root@k8s-master storageclass]# ll /data/k8s/nginxpvc-test/
total 4
-rw-r--r-- 1 root root 27 Feb 25 11:05 index.html
这时候如果删除了与改pvc绑定的pod,并且删除pvc这时候pv会被释放
$ kubectl delete -f nfs-pvc-deploy.yaml
deployment.extensions "nfs-pvc" deleted
service "nfs-pvc" deleted
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
pvc2-nfs Bound pv2-nfs 2Gi RWO 5m
...
$ kubectl delete pvc pvc2-nfs
persistentvolumeclaim "pvc2-nfs" deleted
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
...
pv2-nfs 2Gi RWO Recycle Released default/pvc2-nfs 6m
...
$ ls /data/k8s/
释放后变成了 Released 状态,表示 PVC 已经被释放了,现在可以被重新绑定了,由于我们设置的 PV 的回收策略是 Recycle,所以我们可以很明显的发现 nfs 的共享数据目录下面已经没有了数据了,这是因为我们把 PVC 给删除掉了,然后回收了数据。
------------------------------------------------------
公众号:竹下侯小姜运维
个人博客:https://www.ayunw.cn
重要的事情认真做,普通的事情规范做!
------------------------------------------------------
不定期更新优质内容,技术干货!如果觉得对你有帮助,请扫描下方二维码关注!

温馨提示
如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我!




