目录
4. 持久卷和(PV)、持久卷声明(PVC)和存储类(StorageClass)
本章展示k8s使用存储卷将外部存储挂载到pod容器内,实现数据临时存储或持久化存储。
1. 使用emptyDir卷
apiVersion : v1
kind: Pod
metadata:
name: gitrepo-volume-pod
spec:
containers:
- image: nginx:alpine
name: web-server
volumeMounts:
- name : html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
volumes:
- name : html
emptyDir: {}
emptyDir用于在同一个pod中运行的多个容器之间共享文件,也可以被单个容器用于将数据临时写入磁盘,例如执行排序操作时,没有那么多内存够用。
emptyDir的声明周期与pod相关联,pod删除后,卷的内容会丢失。
emptyDir的实际存储是pod所在节点的磁盘,其性能取决于节点的磁盘类型,通过如下配置可以在内存上创建emptyDir.
volumes:
- name : html
emptyDir:
medium: Memory
2. hostpath卷
hostpath卷指向pod所在节点的文件目录,在同一个节点上运行的pod同时挂载同一个目录可以共享文件,pod将需要持久化的内容输出到挂载路径下,pod删除后其中的内容不会丢失,pod重建时再次自动挂载,真正实现了持久化的卷。
缺点是由于pod删除重建无法保证每次都在同一个节点上,因此pod跨节点时无法保证内容同步。通常hostpath用在单节点集群的持久化,或者需要读取或写入系统文件时才使用。
3.网络存储(NAS)
网络存储类型有很多,例如谷歌的GCE持久磁盘,AWS弹性块存储等,常用的有NFS。
...
volumes:
- name: share-nfs
nfs:
path: /nfs-share
server: 172.10.25.45
...
使用网络存储避免了挂载固定节点的弊端,任何pod或pod漂移到任何节点,都可以同步、共享、持久化内容。
4. 持久卷和(PV)、持久卷声明(PVC)和存储类(StorageClass)
这个一开始不太好理解,多看看就明白了
为什么需要持久卷
不管是hostpath还是NFS,都需要开发人员了解集群中真实的存储结构并且知道服务器地址和路径,这违背了k8s的基础理念,开发人员不需要掌握基础设施的具体状态,并且能使应用程序在云服务商之间能够自由迁移。
理想情况下,应用程序只要告诉k8s需要多大存储,然后由k8s自动分配给应用程序,就像声明cpu和内存一样,应用层不需要知道基础设施的细节。
持久卷的目的是从底层存储技术解耦pod。
如何使用持久卷:
1. 管理员创建持久卷(PV)->开发人员创建持久卷声明(PVC)->PVC自动寻找满足声明需求的PV并绑定->将PVC作为存储卷挂载到pod
2. 还有一种方式不用手动创建PV,先创建存储类(StorageClass),用户创建PVC时指定StorageClass,系统根据StorageClass自动创建PV.
手动模式:
创建持久卷(PV)时指定其大小和可支持的访问模式。
创建持久卷声明(PVC)时指定所需要的最低容量要求和访问模式,k8s将找到可匹配的持久卷(PV)并将其绑定到持久卷声明(PVC).
持久卷声明可以当做pod的一个卷来使用,其他用户不能使用相同的持久卷,除非先删除持久卷声明绑定来释放.
持久卷的存储类型有多种,以nfs为例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-pv
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
nfs:
path: /nfs-share/nginx-pv
server: 172.162.22.43
persistentVolumeReclaimPolicy: Retain
持久卷不属于任何命名空间,它跟节点一样是集群层面的资源,而持久卷声明是属于命名空间的.
访问模式(accessModes)的种类有:
-
RWO --ReadWriteOnce--仅允许单个节点挂载读写
-
ROX--ReadOnlyMany--允许多个节点挂载只读
-
RWX--ReadWriteMany--允许多个节点挂载读写
回收策略(persistentVolumeReclaimPolicy)有三种:
-
Retain--保留--PV在PVC与其解除绑定后,保留其中的内容,并且不会再与其他PVC绑定.
-
Recyle--回收--PVC与PV解绑后,PV清空存储的内容,等待新的PVC与其绑定
-
Delete--删除--PVC与PV解绑后,PV标记为Failed,不可再用,并删除存储的内容
创建持久卷声明(PVC):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: "" # 存储类指定为空会从现有的的pv寻找绑定,否则会根据默认 # storageClass自动创建
查看PVC,可以看到已经与前面创建的nginx-pv是Bound状态.
sudo kubectl get pvc
输出:
--------------------------------------------------------------------
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Bound nginx-pv 1Gi RWO 28s
查看PV,发现绑定到default/nginx-pvc,其中default是命名空间,nginx-pvc是持久卷声明的名称.
sudo kubectl get pv
输出:
---------------------------------------------------------------------
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nginx-pv 1Gi RWO Retain Bound default/nginx-pvc 85m
在pod中使用持久卷声明
apiVersion : v1
kind: Pod
metadata:
name: nginx-volume-pod
spec:
containers:
- image: nginx:alpine
name: web-server
volumeMounts:
- name : html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
volumes:
- name : html
persistentVolumeClaim:
claimName: nginx-pvc
进入pod,可以看到被挂载的持久卷中的内容:
sudo kubectl exec -it nginx-volume-pod sh
df
---------------------------------------------------------------
Filesystem 1K-blocks Used Available Use% Mounted on
172.162.22.43:/nfs-share/nginx-pv
151892992 84325376 67567616 56% /usr/share/nginx/html
下图展示了pod直接使用挂载,和通过持久卷挂载存储的对比
通过使用持久卷和持久卷声明,pod和pvc可以在不同集群间迁移,因为他们不再涉及任何特定依赖于基础设施的内容.
回收持久卷
(策略为Retain的持久卷需手动回收,策略为Recycle和Delete的可自动回收.)
删除pvc后,由于先前设置的PV回收策略是Retain(保留),所以pv不会删除,状态变为Realeased
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM
nginx-pv 1Gi RWO Retain Released default/nginx-pvc 121m
再次创建pvc时,该pv不会被绑到新的pvc(因为Reatin),新的pvc处于pending状态,如果PV的回收策略是Recycle,那么再次创建PVC时,PV会再次绑定
$ sudo kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Pending 10s
这时如果希望继续使用,只能删除和重建PV,重新创建PV稍作等待后PVC又与之自动绑定了.
使用存储类(StorageClass)动态自动创建持久卷
StorageClass(下面简称sc)和PV类似,不属于命名空间,是集群级别的资源
创建sc需要置备程序provisioner,就是一个插件,如果没有的话需要提前配置
创建sc:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nginx-sc
parameters:
archiveOnDelete: 'false'
provisioner: nfs-nfs-base
reclaimPolicy: Delete
volumeBindingMode: Immediate
使用sc创建两个pvc,nginx-pvc 和 nginx-pvc1
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
storageClassName: nginx-sc
查看pvc和pv
$ sudo kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Bound pvc-0c0cbb27-b149-46f5-b10c-4b72340e6e75 100Mi RWO nginx-sc 3m19s
nginx-pvc1 Bound pvc-f137a7c5-511b-4295-8e5a-a9b3dc19184f 100Mi RWO nginx-sc 101s
$ sudo kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-0c0cbb27-b149-46f5-b10c-4b72340e6e75 100Mi RWO Delete Bound default/nginx-pvc nginx-sc 108s
pvc-f137a7c5-511b-4295-8e5a-a9b3dc19184f 100Mi RWO Delete Bound default/nginx-pvc1 nginx-sc 10s
可以看到PV已经自动创建,并且容量和访问策略跟PVC声明的一致。它的回收策略是Delete,因此删除PVC时,PV会自动删除.
使用StorageClass的好处在于,声明时通过名称引用的,只要StorageClass的名称不变,便可以在不同集群间随意移植。