环境:
Ubuntu-1:192.168.114.110作为主
Ubuntu-2:192.168.114.120作为从1,node节点1
Ubuntu-3:192.168.114.130作为从2,node节点2
持久化volumeMounts
pod里面:emptyDir和hostPath。存储在node,NFS...,Cloud
当创建若干个pod后,其容器中的重要数据需要持久化存储,但如果删除了一个pod,则这个容器中的所有数据都将清空,故需要将容器中的数据持久化存储。那么就引入了两个持久化的机制:volumes和volumeMounts。
volumeMounts是pod中的容器内部中的持久化的数据,将其内部的数据挂载到指定的持久化存储目录下。而volumes则是被pod挂载访问的存储目录。它支持同一个pod下的多个容器挂载到该目录下,来达到共享数据的目的。
在持久化存储中,有两种方式:emptyDir,hostPath方式
emptyDir:
emptyDir:当Pod因为某些原因被从节点上删除时,emptyDir卷中的数据也会被永久删除。
volumeMounts:- moutPath: /cachename: cache-volume
volumes:
- name: cache-volumeemptyDir: {}
emptyDir验证:
写一个yaml文件:vim empty.yaml
[root@Node-1 data]#:cat empty.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-empty-dir
spec:containers:- name: empty-dir-containerimage: harbor.hiuiu.com/nginx/nginx:1.21.5volumeMounts:- mountPath: /cachename: cache-volumevolumes:- name: cache-volumeemptyDir: {}
metadata:
name: pod-empty-dir #pod的名字
spec:
containers:
- name:empty-dir-container #镜像的名字
image: harbor.hiuiu.com/nginx/nginx:1.21.5 #镜像,最好在node节点上有本地镜像
volumeMounts: #指定容器中的路径,挂载点
- mountPath: /cache #容器中的目录,会自动创建/cache/这个目录
name: chache-volume #卷名
volumes: #本地挂载点,系统的路径下,默认在/var/lib/kubelet/pods/下
- name: cache-volume #与volumeMounts中的名字一致
emptyDir: {} #emptyDir类型
创建pod:
[root@Node-1 data]#:kubectl apply -f empty.yaml
pod/pod-empty-dir created
查看调度到了哪个node节点上,通过kubectl get pod -o wide发现调度到了从2上,也就是node-3节点。
通过yaml的形式展示出来,过滤出pod的uid。
去从2节点node-3上查看:
[root@Node-3 ~]#:cd /var/lib/kubelet/pods
[root@Node-3 pods]#:ls
20ddc71d-281f-4919-abe7-47c18ecda2f4 e0f4f44f-d8dc-407f-a07e-4a72ba4c9bc3
21b8e3bc-aa44-4dea-9ed7-beac6028ba76
[root@Node-3 pods]#:cd 20ddc71d-281f-4919-abe7-47c18ecda2f4/volumes/kubernetes.io~empty-dir/cache-volume/
[root@Node-3 cache-volume]#:ls
[root@Node-3 cache-volume]#:
这里为空。我们去主node-1上。进入pod里面到/cache/下,创建文件和文件夹。看在node-3上是否生成我们创建的。
[root@Node-1 data]#:kubectl exec -it pod-empty-dir bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod-empty-dir:/# cd /cache/
root@pod-empty-dir:/cache# ls
root@pod-empty-dir:/cache# touch 123
root@pod-empty-dir:/cache# mkdir abc
root@pod-empty-dir:/cache# ls
123 abc
root@pod-empty-dir:/cache# exit
exit
[root@Node-1 data]#:
在node-3上的目录下查看是否创建了abc文件夹和123文件:
[root@Node-3 cache-volume]#:ls
[root@Node-3 cache-volume]#:
[root@Node-3 cache-volume]#:
[root@Node-3 cache-volume]#:ls
123 abc
但如果我们删除了pod后,在node-3上的数据也就一并删除消失:
[root@Node-1 data]#:kubectl delete -f empty.yaml
pod "pod-empty-dir" deleted
[root@Node-1 data]#:kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 10 (55m ago) 6d7h
主上操作删除pod后,去node-3上查看,看是否还存在文件夹abc和123文件:
hostPath:
编写yaml文件:vim hostpath.yaml
[root@Node-1 data]#:cat hostpath.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-hostpath-dir
spec:containers:- name: host-dir-containerimage: harbor.hiuiu.com/nginx/nginx:1.21.5volumeMounts:- mountPath: /usr/share/nginx/htmlname: nginx-volumevolumes:- name: nginx-volumehostPath:path: /data/nginxtype: DirectoryOrCreate
解释说明:
volumes:
- name: nginx-volume #改名字与volumeMounts.name的名字相同
hostPath: #hostPath形式
path: /data/nginx #指定本地挂载点的路径,在/data/nginx/下
type: DirectoryOrCreate #类型指定为DirectoryOrCreate ,如果本地没有这个路径就自动创建
运行创建pod:发现调度到了node-3上。
那么去node-3上查看:发现自动创建了/data/nginx/挂载共享目录。
在主上进入容器中的/usr/share/nginx/html/路径下,创建文件夹和文件,在本地的/data/nginx/下查看是否有我们创建的文件夹和文件。
[root@Node-1 data]#:kubectl exec -it pod-hostpath-dir bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod-hostpath-dir:/# touch /usr/share/nginx/html/123
root@pod-hostpath-dir:/# mkdir /usr/share/nginx/html/abc
root@pod-hostpath-dir:/# exit
exit
[root@Node-1 data]#:
在node-3上查看:
有了我们创建的文件夹和文件。在hostPath类型下,我们删除pod后,node-3上的/data/nginx/下的数据不会被删除。
查看node-3上的/data/nginx/下是否还存在文件夹abc和文件123
依旧存在!实现了数据的持久化存储。相比于emptyDir来说,emptyDir更适合存储一些临时数据。hostPath适合存储永久存储的数据,不丢失。
除此之外,还可以将容器中的多个目录挂载到本机的一个目录挂载点下。
[root@Node-1 data]#:cat hostpath.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-hostpath-dir
spec:containers:- name: host-dir-containerimage: harbor.hiuiu.com/nginx/nginx:1.21.5volumeMounts:- mountPath: /usr/share/nginx/htmlname: nginx-volume- mountPath: /dataname: nginx-volume- mountPath: /mntname: nginx-volumevolumes:- name: nginx-volumehostPath:path: /datas/nginxtype: DirectoryOrCreate
/usr/share/nginx/html
/data
/mnt
都挂在到node节点的/datas/nginx/下
可以发现,调度在了node-3上。在node-3上查看。还没有任何数据。
[root@Node-3 ~]#:cd /datas/nginx/
[root@Node-3 nginx]#:ls
[root@Node-3 nginx]#:
我们在主上进入容器,在三个挂载的共享目录下创建文件,再在node-3上的/datas/nginx/查看:
我们分别在/usr/share/nginx/html/下创建了aaa文件。在/data/下创建了bbb文件。在/mnt/下创建了ccc文件。
[root@Node-1 data]#:kubectl exec -it pod-hostpath-dir bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@pod-hostpath-dir:/# touch /usr/share/nginx/html/aaa
root@pod-hostpath-dir:/# touch /data/bbb
root@pod-hostpath-dir:/# touch /mnt/ccc
root@pod-hostpath-dir:/# exit
exit
[root@Node-1 data]#:
去node-3上查看。发现同时是挂载了容器中的三个目录。持久化的三个目录的数据。
这里在本机的目录下,可以对数据大小做个限制,比如在/datas/nginx/下持久化的数据量不超过500M的数据。
emptyDir:sizeLimit: 500Mi #限额,在本机默认的路径下,限制500M的数据
NFS存储
实操:
nfs存储需要下载nfs。主master上
#安装nfs-kerner-server
[root@Node-1 data]#:apt install -y nfs-kernel-server
添加挂载点:vim /etc/exports,在最后添加一行。重启nfs-kernel-server
#挂载点,添加一行。
[root@Node-1 data]#:vim /etc/exports
/data/disk *(rw,sync,no_root_squash)
#重新生成一下
[root@Node-1 data]#:exportfs -arv
#重启
[root@Node-1 data]#:systemctl restart nfs-kernel-server
[root@Node-1 data]#:mkdir /data/disk
yaml文件:
[root@Node-1 data]#:cat nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deplabels:app: nginx-dep
spec:replicas: 5selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: harbor.hiuiu.com/nginx/nginx:1.21.5imagePullPolicy: IfNotPresentports:- containerPort: 80volumeMounts:- mountPath: /usr/share/nginx/htmlname: nginx-volumevolumes:- name: nginx-volumenfs:server: 192.168.114.110path: /data/diskreadOnly: false
---
apiVersion: v1
kind: Service
metadata:name: my-nodeport
spec:type: NodePortselector:app: nginxports:- port: 90targetPort: 80nodePort: 30008
解释:
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nginx-volume #容器内的路径,指定一个名字,这与volumes的名字相同
volumes:
- name: nginx-volume #这里与volumeMounts中的name匹配。
nfs: #nfs存储
server: 192.168.114.110 #存储的主机
path: /data/disk #宿主机的路径
readOnly: false #只读形式
运行查看pod:
[root@Node-1 data]#:kubectl apply -f nfs.yaml
deployment.apps/nginx-dep created
service/my-nodeport created
[root@Node-1 data]#:kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-dep-6fcb8c557f-g5mmd 1/1 Running 0 3s
nginx-dep-6fcb8c557f-pl7kd 1/1 Running 0 3s
nginx-dep-6fcb8c557f-rgkc9 1/1 Running 0 3s
nginx-dep-6fcb8c557f-w52sw 1/1 Running 0 3s
nginx-dep-6fcb8c557f-wwwhp 1/1 Running 0 3s
nginxtest 1/1 Running 3 (119m ago) 9h
进入容器:写一个主页。在宿主机中看是否存在我们在宿主机中创建的文件。
[root@Node-1 data]#:kubectl exec -it nginx-dep-6fcb8c557f-w52sw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-dep-6fcb8c557f-w52sw:/# echo "nginx-nginx" > /usr/share/nginx/html/index.html
root@nginx-dep-6fcb8c557f-w52sw:/# exit
exit
[root@Node-1 data]#:
[root@Node-1 data]#:cd /data/disk/
[root@Node-1 disk]#:ls
index.html
[root@Node-1 disk]#:cat index.html
nginx-nginx
#访问本机主的地址:端口号
[root@Node-1 disk]#:curl 192.168.114.110:30008
nginx-nginx
PV,PVC
在NFS存储中,由于nfs存储需要指定主机,如果当主机发生改变,就需要修改若干个指定的主机名,为了避免这种情况,就将其分离,分为急群众的一块存储和一个持久化存储卷,于是有了PV,PVC的概念。
PV(PersistentVolume)是集群中的一块存储,由管理员配置或使用存储类动态配置。它是集群中的资源,就像pod是k8s集群资源一样。PV是容器插件,如volumes,其生命周期独立于使用PV的任何单个pod。
PVC(PersistentVolumeClaim)是一个持久化存储卷,我们在创建pod时可以定义这个类型的存储卷,它类似于一个pod,pod消耗节点资源,PVC消耗PV资源,pod可以请求特定级别的资源(如CPU、内存)。PVC在申请PV的时候也可以请求特定的大小和访问模式(例如:可以一次读写或多次只读)。
在创建时的创建顺序:PV --> PVC --> POD
删除顺序:POD --> PVC --> PV
存储区域,需要我们在宿主机指定一个位置。这里我们创建5个PV,创建5个路径,作为我们持久存储的路径。
[root@Node-1 data]#:cd /data
[root@Node-1 data]#:mkdir volume/v{1..5} -p
[root@Node-1 data]#:tree
.
└── volumes├── v1├── v2├── v3├── v4└── v56 directories, 0 files
准备存储服务,添加挂载点:
#在最后添加五行,作为存储点。
[root@Node-1 data]#:vim /etc/exports
......
/data/volume/v1 *(rw,sync,no_root_squash)
/data/volume/v2 *(rw,sync,no_root_squash)
/data/volume/v3 *(rw,sync,no_root_squash)
/data/volume/v4 *(rw,sync,no_root_squash)
/data/volume/v5 *(rw,sync,no_root_squash)
[root@Node-1 data]#:exportfs -arv
[root@Node-1 data]#:systemctl restart nfs-kernel-server
根据顺序,先创建PV:
[root@Node-1 data]#:cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:name: v1
spec:capacity:storage: 1GiaccessModes: ["ReadOnlyMany"]nfs:path: /data/volume/v1server: 192.168.114.110
---
apiVersion: v1
kind: PersistentVolume
metadata:name: v2
spec:capacity:storage: 2GiaccessModes: ["ReadWriteMany"]nfs:path: /data/volume/v2server: 192.168.114.110
---
apiVersion: v1
kind: PersistentVolume
metadata:name: v3
spec:capacity:storage: 3GiaccessModes: ["ReadWriteMany"]nfs:path: /data/volume/v3server: 192.168.114.110
---
apiVersion: v1
kind: PersistentVolume
metadata:name: v4
spec:capacity:storage: 4GiaccessModes: ["ReadWriteOnce"]nfs:path: /data/volume/v4server: 192.168.114.110
---
apiVersion: v1
kind: PersistentVolume
metadata:name: v5
spec:capacity:storage: 5GiaccessModes: ["ReadWriteOnce"]nfs:path: /data/volume/v5server: 192.168.114.110
解释:
我们创建了五个PV,对应着我们创建的五个路径下的存储位置Path。
accessModes:定义了卷可以被访问的模式:accessModes字段是一个数组,它定义了PV的访问模式,访问模式决定了PV可以被如何访问和挂载。kubernetes定义了以下几种访问模式。
ReadWriteOnde(RWO):卷可以被单个节点以读写模式挂载。
ReadOnlyMany(ROX):卷可以被多个节点以只读模式挂载。
ReadWriteMany(RWX):卷可以被多个节点以读写模式挂载。
一个卷被多个系统挂载,都使用文件系统,只被单独pod挂载的无状态服务使用块,也可以使用文件系统。
注意:并非所有的存储类型都支持所有的访问模式。例如:NFS类型的PV通常支持ReadWriteMany和ReadOnlyMany,但某些块存储可能只支持ReadWriteOnce。
创建PVC:
[root@Node-1 data]#:cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:name: my-pvc
spec:accessModes: ["ReadWriteMany"]resources:requests:storage: 2Gi
解释:
PVC和PV绑定:自动匹配并绑定。这里的name: my-pvc让pod指向这里的名字做关联。
控制平面中的控制回路检测新的PVC对象,寻找与之匹配的PV(如果可能的话),并将二者绑定到一起,如果找不到匹配的PV卷,PVC申领会无限期地处于未绑定状态。当与之匹配的PV卷,也无法与请求100Gi大小的存储的PVC匹配。当新的100Gi PV卷被加入到集群时,该PVC才有可能被绑定。
Pod将PVC申领当做存储卷来使用,集群会检视PVC申领,找到所绑定的卷,并为pod挂载该卷,对于支持多种访问模式的卷,用户要在pod中以卷的形式使用申领时指定期望的访问模式。
一旦用户有了申领对象并且该申领已经被绑定,则所绑定的PV卷在用户仍然需要它期间一直属于该用户。用户通过在Pod的volumes块中包含persistentVolumeClaim节区来调度pod,访问所申领的PV卷。
创建Pod
[root@Node-1 data]#:cat pod.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-pvc
spec:containers:- name: nginximage: harbor.hiuiu.com/nginx/nginx:1.21.5imagePullPolicy: IfNotPresentvolumeMounts:- name: nginx-htmlmountPath: /usr/share/nginx/htmlvolumes:- name: nginx-htmlpersistentVolumeClaim:claimName: my-pvc
要关联的pvc名。
运行pv:创建了五个pv。分别在对应的路径下。且Available为待使用状态。
运行pvc:
再次查看pv:看pvc找到了哪个pv。其实观察不难发现。pvc与pv的关联是通过accessModes和storage。由于pvc中的accessModes为RWX,而v1,v2,v3都是RWX。但是v2的storage为2Gi与PVC的一致,能够匹配到最精确。所以PVC关联了v2。查看:
发现pvc与v2处于绑定状态。
创建pod
查看一下调度到了哪个pod以及ip地址
发现调度到了node-2主机上。ip为10.200.247.14
使用curl测试:已经成功访问到了,由于没有主页。
可以进入容器创建一个主页。我们共享的pod目录是/usr/share/nginx/html
宿主机位置是:/data/volume/v2下。
这里创建时先创建pv,再创建pvc,后创建pod。
删除时先删除pod,再删除pvc,后删除pv。kubectl delete -f pod.yaml
这里pvc是与v3做的绑定。根据我们pv的创建属性。我们可以设置pvc来实现绑定指定的pv。比如删除后修改pvc的属性,让其与v5绑定。我们pv中v5是ReadWriteOnce和5Gi。
先删除pod,再删除pvc。修改pvc:
到这里,pod和pvc是被删除的,pvc也修改了。在运行pvc前先查看下pv和pvc的状态。
我们运行pvc就会与v5绑定。
其实也可以修改pv,使其与pvc中的属性相指定。
注意:pv中的storage: 这个大小必须大于或等于pvc中的storage: 大小。这里pvc中如果是4.2Gi,则也会绑定5Gi的v5。与保留整数无关。
---end---