首先我们会学习Volume, 以及Kubernetes如何通过Volume 为集群中的容器提供存储;然后我们会实践几种常用的Volume 类型并理解它们各自的应用场景;最后,我们会讨论Kubernetes如何通过Persistent Volume和Persistent Volume Claim分离集群管理员与集群用户的职责,并实践Volume的静态供给和动态供给。
emptyDir是最基础的Volume类型。正如其名字所示,一个emptyDir Volume是Host上的一个空目录。emptyDir Volume 对于容器来说是持久的,对于Pod则不是。当Pod从节点删除时,Volume的内容也会被删除。但如果只是容器被销毁而Pod还在,则Volume不受影响。也就是说: emptyDir Volume的生命周期与Pod-致。
Pod中的所有容器都可以共享Volume, 它们可以指定各自的mount 路径。
apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
spec:
containers:
- name: producer
image: wangjinxiong/nginx:tools
volumeMounts:
- name: shared-volume
mountPath: /usr/share/nginx/html # (2)
volumes:
- name: shared-volume # (1)
emptyDir: {}
(1) 文件最底部volumes 定义了一个emptyDir 类型的Volume shared-volume
(2 ) 将volume shared-volume 挂载到容器producer的/usr/share/nginx/html
通过docker命令可以查看,可以看到shared-volume的保存目录。
docker inspect d30522745908 # 通过docker ps | grep producer-consumer查看ID
........
"Mounts": [
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/02c1e853-e863-4dc6-8b5a-91e08a8592f4/volumes/kubernetes.io~empty-dir/shared-volume",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
emptyDir是Host上创建的临时目录,其优点是能够方便地为Pod中的容器提供共享存储,不需要额外的配置。它不具备持久性,如果Pod 不存在了,emptyDir 也就没有了。根据这个特性,emptyDir特别适合Pod中的容器需要临时共享存储空间的场景,比如前面的生产者消费者用例。
hostPathVolume的作用是将DockerHost文件系统中已经存在的目录mount给Pod的容器。大部分应用都不会使用hostPath Volume,因为这实际上增加了Pod 与节点的耦合,限制了Pod 的使用。不过那些需要访问Kubernetes 或Docker 内部数据(配置文件和二进制库)的应用则需要使用hostPath。比如kube- apiserver和kube- controller-manager就是这样的应用,通过kubectl edit --namespace=kube -system pod kube- apiserver- k8s-master查看kube-apiserver Pod的配置,Volume的相关部分如图9-5所示。
volumeMounts:
- mountPath: /etc/ssl/certs
name: ca-certs
readOnly: true
- mountPath: /etc/pki
name: etc-pki
readOnly: true
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
hostNetwork: true
nodeName: k8s-master
preemptionPolicy: PreemptLowerPriority
priority: 2000001000
priorityClassName: system-node-critical
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
operator: Exists
volumes:
- hostPath:
path: /etc/ssl/certs
type: DirectoryOrCreate
name: ca-certs
- hostPath:
path: /etc/pki
type: DirectoryOrCreate
name: etc-pki
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
这里定义了三个hostPath: volume k8s、 certs 和pki, 分别对应Host目录/etc/kubermetes、/etc/ssl/certs和/etc/pki. 如果Pod被销毁了,hostPath 对应的目录还是会被保留,从这一.点来看,hostPath 的持久性比emptyDir 强。不过- -旦Host 崩溃,hostPath 也就无法访问了。
hostpath 宿主机本地目录保存,pod删除时不会删除数据,但宿主机故障不能迁移到其他nodes节点。
apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
spec:
containers:
- name: producer
image: wangjinxiong/nginx:tools
volumeMounts:
- name: shared-volume
mountPath: /usr/share/nginx/html # (2)
volumes:
- name: shared-volume
hostPath:
path: /tmp #(1)
type: Directory
(1) 文件最底部volumes 定义了一个hostpath 类型的Volume shared-volume
(2 ) 将volume shared-volume 挂载到容器producer的/usr/share/nginx/html
通过docker命令可以查看,可以看到shared-volume的保存目录。
docker inspect 8ab46de51ba2 # 通过docker ps | grep producer-consumer查看ID
"Mounts": [
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/03aa0d37-c68f-46a6-8353-f275b0101a57/etc-hosts",
"Destination": "/etc/hosts",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Source": "/var/lib/kubelet/pods/03aa0d37-c68f-46a6-8353-f275b0101a57/containers/producer/95e21b36",
"Destination": "/dev/termination-log",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
{
"Type": "bind",
"Source": "/tmp",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
},
PersistentVolumeClaim (PVC) 是对 PV的申请(Claim) 。PVC通常由普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的PV。有了PersistentVolumeClaim, 用户只需要告诉Kubernetes 需要什么样的存储资源,而不
必关心真正的空间从哪里分配、如何访问等底层细节信息。这些Storage Provider的底层信息交给管理员来处理,只有管理员才应该关心创建PersistentVolume 的细节信息。
作为准备工作,我们已经在k8s-master 节点上搭建了一个NFS服务器,目录为/nfsdata。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0908
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
nfs:
path: /nfsdata
server: 10.0.12.16
# kubectl apply -f pv0908.yaml
persistentvolume/pv0908 created
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv0908 5Gi RWX Retain Available 7s
STATUS为Available, 表示pv0908就绪,可以被PVC申请。
pvc的yaml文件:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc0908
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
[root@k8s-master ~]# kubectl apply -f pvc0908.yaml
persistentvolumeclaim/pvc0908 created
[root@k8s-master ~]# kubectl apply -f pvc0908.yaml ^C
[root@k8s-master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc0908 Bound pv0908 5Gi RWX 5s
[root@k8s-master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv0908 5Gi RWX Retain Bound default/pvc0908 7m18s
从kubectl get pvc和kubectl get pv的输出可以看到pv0908已经Bound到pv0908,申请成功。
apiVersion: v1
kind: Pod
metadata:
name: nginx0908
spec:
containers:
- name: nginx
image: wangjinxiong/nginx:tools
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim:
claimName: pvc0908
进入容器:
# kubectl exec -it nginx0908 -- /bin/bash
root@nginx0908:/# cd /usr/share/nginx/html/
root@nginx0908:/usr/share/nginx/html# echo "wangjinxiong" > index.html
访问pod的主页:
# kubectl get pod -o wide | grep nginx0908
nginx0908 1/1 Running 0 5m53s 172.18.235.197 k8s-master <none> <none>
# curl 172.18.235.197
wangjinxiong
查看后端存储:
# kubectl describe pv pv0908
Name: pv0908
Labels: <none>
Annotations: pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pv-protection]
StorageClass:
Status: Bound
Claim: default/pvc0908
Reclaim Policy: Retain
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 5Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 10.0.12.16
Path: /nfsdata
ReadOnly: false
Events: <none>
# 查看nfs文件
# cd /nfsdata/
[root@k8s-master nfsdata]# ls
index.html
**AccessModes(访问模式): **
AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
• ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
• ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
• ReadWriteMany(RWX):读写权限,可以被多个节点挂载
*RECLAIM POLICY(回收策略): **
目前 PV 支持的策略有三种:
• Retain(保留): 保留数据,需要管理员手工清理数据 , 默认。
• Recycle(回收):清除 PV 中的数据,效果相当于执行 rm -rf /ifs/kuberneres/
• Delete(删除):与 PV 相连的后端存储同时删除
**STATUS(状态): **
一个 PV 的生命周期中,可能会处于4中不同的阶段:
• Available(可用):表示可用状态,还未被任何 PVC 绑定
• Bound(已绑定):表示 PV 已经被 PVC 绑定
• Released(已释放):PVC 被删除,但是资源还未被集群重新声明
• Failed(失败): 表示该 PV 的自动回收失败
在前面的例子中,我们提前创建了PV, 然后通过PVC申请PV并在Pod中使用,这种方式叫作静态供给( Static Provision)。与之对应的是动态供给(Dynamical Provision),即如果没有满足PVC 条件的PV,会动态创建PV。 相比静态供给,动态供给有明显的优势:不需要提前创建PV,减少了管理员的工作量,效率高。动态供给是通过StorageClass 实现的,StorageClass 定义了如何创建PV,下面给出两个例子。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc0908-nfs
annotations:
volume.beta.kubernetes.io/storage-provisioner: nfs-provisioner-01
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: nfs-server
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx0908
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nginx0908
template:
metadata:
labels:
app: nginx0908
spec:
volumes:
- name: host-time
hostPath:
path: /etc/localtime
type: ''
- name: pvc0908-nfs
persistentVolumeClaim:
claimName: pvc0908-nfs
containers:
- image: wangjinxiong/nginx:tools
name: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web80
volumeMounts:
- mountPath: /etc/localtime
name: host-time
readOnly: true
- name: pvc0908-nfs
mountPath: /usr/share/nginx/html
查看pvc相关情况:
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc0908-nfs Bound pvc-fab208e9-ca70-4129-8d67-78d89011e726 2Gi RWX nfs-server 18m
# kubectl describe pv pvc-fab208e9-ca70-4129-8d67-78d89011e726
Name: pvc-fab208e9-ca70-4129-8d67-78d89011e726
Labels: <none>
Annotations: pv.kubernetes.io/provisioned-by: nfs-provisioner-01
Finalizers: [kubernetes.io/pv-protection]
StorageClass: nfs-server
Status: Bound
Claim: default/pvc0908-nfs
Reclaim Policy: Delete
Access Modes: RWX
VolumeMode: Filesystem
Capacity: 2Gi
Node Affinity: <none>
Message:
Source:
Type: NFS (an NFS mount that lasts the lifetime of a pod)
Server: 10.0.12.16
Path: /nfsdata/default-pvc0908-nfs-pvc-fab208e9-ca70-4129-8d67-78d89011e726
ReadOnly: false
Events: <none>
nfs server情况:
# cd /nfsdata/
# ls
default-pvc0908-nfs-pvc-fab208e9-ca70-4129-8d67-78d89011e726
#
下一篇:8 secret and configmap