概述
介绍kubernetes中为什么需要使用存储
volume的基本管理方式
怎样创建PVC与PV
结合实际场景怎样使用NFS存储
1. volume介绍与管理
pod里面定义的一种属性值
在dokcer的设计实现中,容器中的数据是临时的,当容器被销毁时,其中的数据将会丢失。如果需要(有状态的服务)持久化数据(集群或者日志),那么就需要使用docker数据卷挂载宿主机上的文件或者目录到容器中。在kubernetes中,当pod重建的时候,数据会丢失,另外,一个pod中同时运行多个容器时,容器之间需要共享文件,所以kubernetes通过数据卷挂载的方式来提供pod数据的持久化。
1.1 区别于docker的volume
docker也有volume概念,但对它只有少量且松散的管理。在docker中,volume是磁盘上或者另外一个容器内的目录。虽然docker现在也能提供volume驱动程序,但是目前功能还非常有限(截止docker1.7,每个容器只允许有一个volume驱动程序,并且无法将参数传递给卷,并且支持的存储驱动有限)。
1.2 声明方式
使用卷时,Pod声明中需要提供卷的类型(.spec.volumes
字段)和卷挂载的位置(.spec.containers.volumeMounts
字段)
1.3 kubernetes中常用支持的卷类型
目前kubernetes支持的数据全,类型如下:
类型 | 说明 |
---|---|
EmptyDir | 单节点存储 |
HostPath | 单节点存储 |
GCE Persistent Disk | 谷歌云存储 |
AWS Elastic Block Store | AWS云存储 |
NFS | 网络文件系统 |
iSCSI | |
GlusterFS | |
RBD | ceph块存储 |
Persistent Volume Claim(PVC) |
图解volume在kubernetes中的位置
1.4 kubernetes哪些资源对象使用volume?
Pod
1.3.1 案例一:挂载hostpath到pod
hostPath 卷能将主机节点文件系统上的文件或目录挂载到您的 Pod 中。
把主机中的/data/nginx/log目录挂载到pod中的/var/log/nginx目录
需要在所有节点创建目录/data/nginx/log
node01&node02
mkdir -p /data/nginx/log
master01
mkdir -p /root/volume && cd /root/volume
cat >demo-mount-hostpath.yaml<<EOF
apiVersiono: v1
kind: Pod
metadata:
name: pod-hostpath
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-log
mountPath: /var/log/nginx
volumes:
- name: nginx-log
hostPath:
path: /data/nginx/log
EOF
启动nginx服务
[root@master01 volume]# kubectl apply -f demo-mount-hostpath.yaml
pod/pod-hostpath created
[root@master01 volume]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-hostpath 1/1 Running 0 20s 172.17.15.13 192.168.68.149 <none> <none>
启用dnstools容器,测试nginx访问,并在node01上查看日志文件内容
[root@master01 volume]# kubectl run -it --rm --restart=Never --image=infoblox/dnstools:latest dnstools
If you don‘t see a command prompt, try pressing enter.
dnstools# curl 172.17.15.13
[root@node01 log]# tail access.log -f
172.17.15.14 - - [18/Aug/2020:04:15:32 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-"
1.3.2 案例二:挂载空目录到POD
emptyDir类型的volume在pod分配到node上时被创建,kubernetes会在node上自动分配一个目录,因此无需指定宿主机node上对应的目录文件。这个目录的初始内容为空,当pod从node上移除时,emptyDir中的数据会被永久删除。
说明:容器崩溃并不会导致Pod从节点上移除,因此容器崩溃时emptyDir卷中的数据是安全的。
emptyDir Volume主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等。
Pod示例:
cat > demo-mount-emptydir.yaml<<EOF
apiVersiono: v1
kind: Pod
metadata:
name: pod-emptydir
spec:
containers:
- name: test-container
image: patsys/test-webserver
volumeMounts:
- name: cache-volume
mountPath: /cache
volumes:
- name: cache-volume
emptyDir: {}
EOF
测试:
从master上打开新建的pod-emptydir的终端,在/cache目录下创建一个测试文件test.txt,在node01上可以查看到在pod里创建的文件,删除pod以后,文件也被移除。
[root@master01 volume]# kubectl exec -it nginx-7bb7cd8db5-5h2d5 /bin/sh
/ # cd /cache/
/cache # ls
/cache # touch test.txt
test.txt
#node01
find / -name "test.txt"
/var/lib/kubelet/pods/d80a3125-8b2d-485d-9096-e7053797ee93/volumes/kubernetes.io~empty-dir/cache-volume/test.txt
[root@master01 volume]# kubectl delete -f demo-mount-emptydir.yaml
pod "pod-emptydir" deleted
[root@node01 cache-volume]# find / -name "test.txt"
[root@node01 cache-volume]#
2. PersistentVolume 与 Persistent Volume Claim
2.1 持久卷Persistent Volume(PV)
PV是由管理员设置的存储卷,它是集群的一部分,就像节点是集群中的资源一样,PV也是集群中的资源。PV是与Vloume类似的卷插件,具有独立的生命周期。
2.1.1 配置方式
动态和静态方式
推荐的方式是使用动态配置
2.1.2 PV回收策略
PV可以由多种回收策略,包括“Retain”,“Recycle”,“Delete”。对于动态配置的PV来说,默认回收策略为“Delete”。
"delete",表示当用户删除对应的PVC的时候,动态配置的volume将自动删除。
"Retain",如果用户删除PVC,对应的PV不会被删除。相反,它将变成Released状态,表示所有的数据可以被手动恢复。
"Recycle" 该策略已被弃用。
2.1.3 列出PV
[root@master01 volume]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-957bd492-cf4c-4a01-92b7-c76fded6c538 5Gi RWX Delete Bound monitoring/prometheus-data managed-nfs-storage 5d20h
pvc-a0ff4b83-c9f3-430e-92fb-d95878db0f51 5Gi RWO Delete Bound monitoring/grafana managed-nfs-storage 5d20h
2.1.4 修改PV回收策略
选择PV中的一个并更改它的回收策略
kubectl patch pv <your-pv-name> -p ‘{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}‘
2.1.5 PV的访问模式
- ReadWriteOnce:最基本的方式,可读可写,单个pod挂载。
- ReadOnlyMany:可以以只读的方式被多个pod挂载。
- ReadWriteMany:可以以读写的方式被多个pod挂载。
注意:不是每一种存储都支持这三种方式,如共享方式,目前支持的还不多(数据一致性问题),通常简单的实现为NFS。所以在PVC绑定PV时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
2.1.6 PV支持的存储驱动
NFS,ISCSI,RBD,HostPath
2.2 Persistent Volume Claim(PVC)
PVC是用户对存储PV的请求,它与POD相似,pod消耗节点资源,PVC消耗PV资源。pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定大小和访问模式(例如:可以以读写一次或者只读多次模式挂载)。集群管理员还可以使用StorageClasses来设置动态提供存储。
2.2.1 PVC存储挂载过程
- 集群管理员创建由物理存储支持的PV。管理员不将卷与任何pod关联。
- 集群用户创建一个PVC,它将自动绑定到合适的PV。
- 用户创建一个使用PVC作为存储的pod。
2.2.2 PV与volume的区别
- PV只能是网络存储,不属于任何的节点,必须可以在每个节点上可以访问。
- PV不是定义在pod上,而是独立于pod,是属于kubernetes存储的一部分。
- PV目前支持的类型:NFS,ISCSI,RBD,HostPath
- volume与使用它的pod之间是一种静态绑定关系,是定义pod里面的一种属性,同时定义了它使用的volume的类型。
- volume无法单独创建,因为它不是独立的kubernetes资源对象。
2.2.3 案例一:PVC挂载NFS(以部署grafana服务为例)
2.2.3.1 安装NFS服务
我们在安装监控的时候已经安装了NFS,并且创建了PV,分别挂载到prometheus和grafana两个服务的POD上。
创建NFS的过程参考“第六课:部署集群监控系统”
2.2.3.2 关联NFS到PV
参考我们之前配置监控服务的时候创建的NFS存储,同时创建的2个PV
[root@master01 grafana]# kubectl get pv pvc-957bd492-cf4c-4a01-92b7-c76fded6c538 -o yaml
apiVersion: v1
kind: PersistentVolume
metadata:
annotations:
pv.kubernetes.io/provisioned-by: fuseim.pri/ifs
creationTimestamp: "2020-08-13T04:54:09Z"
finalizers:
- kubernetes.io/pv-protection
name: pvc-957bd492-cf4c-4a01-92b7-c76fded6c538
resourceVersion: "414964"
selfLink: /api/v1/persistentvolumes/pvc-957bd492-cf4c-4a01-92b7-c76fded6c538
uid: 9d3e3cb5-76ee-42af-9fe5-93a953c7cbc1
spec:
accessModes:
- ReadWriteMany #访问模式[ReadWriteOnce|ReadOnlyMany|ReadWriteMany]
capacity: #容量
storage: 5Gi #PV可用的大小
claimRef:
apiVersion: v1
kind: PersistentVolumeClaim
name: prometheus-data
namespace: monitoring
resourceVersion: "414957"
uid: 957bd492-cf4c-4a01-92b7-c76fded6c538
nfs: #NFS配置
path: /ifs/kubernetes/monitoring-prometheus-data-pvc-957bd492-cf4c-4a01-92b7-c76fded6c538 #NFS路径
server: 192.168.68.146 #NFSserver地址
persistentVolumeReclaimPolicy: Delete #回收策略[Delete|Retain|Recycle]
storageClassName: managed-nfs-storage #存储类名称
volumeMode: Filesystem
status:
phase: Bound
2.2.3.3 创建PVC
创建PVC并关联到PV,主要关注点:存储类的名称,访问模式,存储空间请求。
[root@master01 grafana]# more grafana-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: grafana
namespace: monitoring
spec:
storageClassName: managed-nfs-storage #存储类名称,与PV文件中spec:storageClassName相对应
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
2.2.3.4 pod关联pvc
创建使用该PVC的Pod
[root@master01 grafana]# more grafana-deployment.yaml
...
seec:
containers:
volumes:
- name: grafana-storage
persistentVolumeClaim:
claimName: grafana #关联PVC的名称,与PVC.yaml内的metadata:name对应
2.3 StorageClass
为PVC动态分配PV
每个StorageClass都有一个分配器,用来决定使用哪个卷插件分配PV。
2.3.1 StorageClass
在kubernetes中,用户使用pod需要持久化数据(集群),通常情况下,需要集群管理员手工创建PV,然后用户绑定在POD中,提供给pod中的集群使用。假设在大规模的情况下,如果每次都是需要管理员人工创建PV,那么严重影响效率,所以引入了StorageClass,让PVC通过StorageClass自动创建PV。
2.3.2 StorageClass支持的卷插件
- AWS Elastic Block Store
- RBD
- Local
- GlusterFS
- CephFS
2.3.3 StorageClass创建PV流程
- 集群管理员预先创建存储类(storageclass)
- 用户创建pod,pod中使用指定存储类的持久化存储声明(PVC)
- 存储持久化声明(PVC)通知系统,需要一个持久化存储(PV)
- 系统读取存储类信息
- 系统基于存储类的信息,在后台自动创建PVC需要的PV
- 在后台创建完成PV之后,PVC绑定到PV,进行数据的持久化处理
- POD通过PVC持久化存储数据
2.3.4 案例分析:监控服务存储部署
1.管理员预先创建存储类storageclass名称为:managed-nfs-class
每个sotrageclass都包含provisioner
,parameters
,reclaimPolicy
字段,这些字段在storageclass需要动态分配PV时会用到。
[root@master01 nfs]# more nfs-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment‘s env PROVISIONER_NAME‘ 匹配nfs-deployment.yaml中env:name:PROVISIONER_NAME
parameters:
archiveOnDelete: "true"
2.创建nfs服务
[root@master01 nfs]# more nfs-deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
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
imagePullPolicy: IfNotPresent
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME #这里的提供者字段需要与storageclass里的想对应
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.68.146
- name: NFS_PATH
value: /ifs/kubernetes
volumes:
- name: nfs-client-root
nfs:
server: 192.168.68.146
path: /ifs/kubernetes
3.声明PVC
创建pvc名称为grafana,关联存储类stroageclass的名称为前面我们创建的managed-nfs-storage
[root@master01 grafana]# more grafana-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: grafana
namespace: monitoring
spec:
storageClassName: managed-nfs-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
4.PVC会自动生成一个PV,并绑定到PVC
[root@master01 grafana]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-a0ff4b83-c9f3-430e-92fb-d95878db0f51 5Gi RWO Delete Bound monitoring/grafana managed-nfs-storage 6d2h
这里的PV名称为pvc-a0ff4b83-c9f3-430e-92fb-d95878db0f51并不是我们手动创建的,而是系统通过PVC在后台自动生成的,并且绑定到名称为grafana的pvc上。
5.在创建服务的deployment文件中引用PVC
[root@master01 grafana]# more grafana-deployment.yaml
...
volumes:
- name: grafana-storage
persistentVolumeClaim:
claimName: grafana
...
6.启动POD后,数据会持久化到nfs上
[root@master01 monitoring-grafana-pvc-a0ff4b83-c9f3-430e-92fb-d95878db0f51]# ll
total 1752
-rw-r--r-- 1 nfsnobody nfsnobody 1794048 Aug 19 15:01 grafana.db
drwxr-xr-x 3 nfsnobody nfsnobody 36 Aug 14 14:28 plugins
drwx------ 2 nfsnobody nfsnobody 6 Aug 13 12:53 png