目录
1、k8s持久化存储:emptyDir
emptyDir类型的Volume是在Pod分配到Node上时被创建,Kubernetes会在Node上自动分配一个目录,因此无需指定宿主机Node上对应的目录文件。 这个目录的初始内容为空,当Pod从Node上移除时,emptyDir中的数据会被永久删除。emptyDir Volume主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等。
[root@hd1.com ~]# cat emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-empty
spec:
containers:
- name: container-empty
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- emptyDir: {}
name: cache-volume
查看本机临时目录存在的位置,可用如下方法:
#查看pod调度到哪个节点
[root@hd1.com ~]# kubectl get pods -o wide | grep empty
pod-empty 1/1 Running 0 10.244.209.152 hd2.com
#查看pod的uid
[root@hd1.com ~]# kubectl get pods pod-empty -o yaml | grep uid
uid: 38d60544-8591-468d-b70d-2a66df3a1cf6
#登录到hd2.com上
[root@hd2.com ~]# tree /var/lib/kubelet/pods/38d60544-8591-468d-b70d-2a66df3a1cf6
/var/lib/kubelet/pods/38d60544-8591-468d-b70d-2a66df3a1cf6
├── containers
│ └── container-empty
│ └── c9e06d01
├── etc-hosts
├── plugins
│ └── kubernetes.io~empty-dir
│ ├── cache-volume
│ │ └── ready
│ └── wrapped_default-token-cq5qp
│ └── ready
└── volumes
├── kubernetes.io~empty-dir
│ └── cache-volume
│ └── aa
└── kubernetes.io~secret
└── default-token-cq5qp
├── ca.crt -> ..data/ca.crt
├── namespace -> ..data/namespace
└── token -> ..data/token
12 directories, 7 files
由上可知,临时目录在本地的/var/lib/kubelet/pods/38d60544-8591-468d-b70d-2a66df3a1cf6/volumes/kubernetes.io~empty-dir/cache-volume/下。
2、k8s持久化存储:hostPath
hostPath Volume是指Pod挂载宿主机上的目录或文件。 hostPath Volume使得容器可以使用宿主机的文件系统进行存储,hostpath(宿主机路径):节点级别的存储卷,在pod被删除,这个存储卷还是存在的,不会被删除,所以只要同一个pod被调度到同一个节点上来,在pod被删除重新被调度到这个节点之后,对应的数据依然是存在的。
[root@hd1.com ~]# cat hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- image: nginx
name: test-nginx
volumeMounts:
- mountPath: /test-nginx
name: test-volume
- image: tomcat:8.5-jre8-alpine
name: test-tomcat
volumeMounts:
- mountPath: /test-tomcat
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data1
type: DirectoryOrCreate
注意:
# DirectoryOrCreate表示本地有/data1目录,就用本地的,本地没有就会在pod调度到的节点自动创建一个。
验证:
#查看pod调度到了哪个物理节点
[root@hd1.com ~]# kubectl get pods -o wide | grep hostpath
test-hostpath 2/2 Running 10.244.209.153 hd2.com
#由上面可以知道pod调度到了hd2.com上,登录到hd2.com机器,查看是否在这台机器创建了存储目录
[root@hd2.com ~]# ll /data1/
total 0
#上面可以看到已经创建了存储目录/data1,这个/data1会作为pod的持久化存储目录
#在hd2.com上的/data1下创建一个目录
[root@hd2.com ~]# cd /data1/
[root@hd2.com data1]# mkdir aa
#测试存储卷是否可以正常使用,登录到nginx容器
[root@hd1.com ~]# kubectl exec -it test-hostpath -c test-nginx -- /bin/bash
root@test-hostpath:/# cd /test-nginx/
#/test-nginx/目录存在,说明已经把宿主机目录挂载到了容器里
root@test-hostpath:/test-nginx# ls
aa
#测试存储卷是否可以正常使用,登录到tomcat容器
[root@hd1.com ~]# kubectl exec -it test-hostpath -c test-tomcat -- /bin/bash
root@test-hostpath:/usr/local/tomcat# cd /test-tomcat/
#/test-tomcat/目录存在,说明已经把宿主机目录挂载到了容器里
root@test-hostpath:/test-tomcat# ls
aa
#通过上面测试可以看到,同一个pod里的test-nginx和test-tomcat这两个容器是共享存储卷的。
hostpath存储卷缺点:
单节点
pod删除之后重新创建必须调度到同一个node节点,数据才不会丢失
如何调度到同一个nodeName呢 ? 需要我们再yaml文件中进行指定就可以啦
[root@hd1 volume]# cat hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
nodeName: hd3.com
containers:
- image: nginx
3、k8s持久化存储:nfs
上节说的hostPath存储,存在单点故障,pod挂载hostPath时,只有调度到同一个节点,数据才不会丢失。那可以使用nfs作为持久化存储。
3.1、搭建nfs服务
以k8s的控制节点作为NFS服务端
[root@hd1.com ~]# yum install nfs-utils -y
#在宿主机创建NFS需要的共享目录
[root@hd1.com ~]# mkdir /data/volumes -pv
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/volumes’
#配置nfs共享服务器上的/data/volumes目录
[root@hd1.com ~]# systemctl start nfs
[root@hd1.com ~]# vim /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
#no_root_squash: 用户具有根目录的完全管理访问权限 squash 表示挤压,no表示否定,不对root的权限做挤压
#使NFS配置生效
[root@hd1.com ~]# exportfs -arv
exporting 192.168.1.0/24:/data/volumes
[root@hd1.com ~]# service nfs start
Redirecting to /bin/systemctl start nfs.service
#设置成开机自启动
[root@hd1.com ~]# systemctl enable nfs
#查看nfs是否启动成功
[root@hd1.com ~]# systemctl status nfs
Active: active
看到nfs是active,说明nfs正常启动了
yum install nfs-utils -y
systemctl enable nfs
3.2创建Pod,挂载NFS共享出来的目录
[root@hd1.com ~]# cat nfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-nfs-volume
spec:
containers:
- name: test-nfs
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- name: nfs-volumes
mountPath: /usr/share/nginx/html
volumes:
- name: nfs-volumes
nfs:
path: /data/volumes
server: 192.168.1.11
注:path: /data/volumes #nfs的共享目录
server:192.168.1.11是hd1.com机器的ip,这个是安装nfs服务的地址
#更新资源清单文件
[root@hd1.com ~]# kubectl apply -f nfs.yaml
#查看pod是否创建成功
[root@hd1.com volumes]# kubectl get pods -o wide | grep nfs
test-nfs-volume 1/1 Running 10.244.187.108 hd3.com
#登录到nfs服务器,在共享目录创建一个index.html
root@hd1.com volumes]# pwd
/data/volumes
[root@hd1.com volumes]# cat index.html
Helloworld
#请求pod,看结果
[root@hd1.com volumes]# curl 10.244.187.108
helloworld
#通过上面可以看到,在共享目录创建的index.html已经被pod挂载了
#上面说明挂载nfs存储卷成功了,nfs支持多个客户端挂载,可以创建多个pod,挂载同一个nfs服务器共享出来的目录;但是nfs如果宕机了,数据也就丢失了,所以需要使用分布式存储,常见的分布式存储有glusterfs和cephfs。
4、k8s持久化存储: PVC
4.1 k8s PV
PersistentVolume(PV)是群集中的一块存储,由管理员配置或使用存储类动态配置。 它是集群中的资源,就像pod是k8s集群资源一样。 PV是容量插件,如Volumes,其生命周期独立于使用PV的任何单个pod。
4.2 k8s PVC
PersistentVolumeClaim(PVC)是一个持久化存储卷,我们在创建pod时可以定义这个类型的存储卷。 它类似于一个pod。 Pod消耗节点资源,PVC消耗PV资源。 Pod可以请求特定级别的资源(CPU和内存)。 pvc在申请pv的时候也可以请求特定的大小和访问模式(例如,可以一次读写或多次只读)。
4.3 k8s PVC和PV工作原理
PV是群集中的资源。 PVC是对这些资源的请求。
PV和PVC之间的相互作用遵循以下生命周期:
(1)pv的供应方式
可以通过两种方式配置PV:静态或动态。
静态的:
集群管理员创建了许多PV。它们包含可供群集用户使用的实际存储的详细信息。它们存在于Kubernetes API中,可供使用。
动态的:
当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,群集可能会尝试为PVC专门动态配置卷。此配置基于StorageClasses,PVC必须请求存储类,管理员必须创建并配置该类,以便进行动态配置。
(2)绑定
用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态
(3)使用
a)需要找一个存储服务器,把它划分成多个存储空间;
b)k8s管理员可以把这些存储空间定义成多个pv;
c)在pod中使用pvc类型的存储卷之前需要先创建pvc,通过定义需要使用的pv的大小和对应的访问模式,找到合适的pv;
d)pvc被创建之后,就可以当成存储卷来使用了,我们在定义pod时就可以使用这个pvc的存储卷
e)pvc和pv它们是一一对应的关系,pv如果被pvc绑定了,就不能被其他pvc使用了;
f)我们在创建pvc的时候,应该确保和底下的pv能绑定,如果没有合适的pv,那么pvc就会处于pending状态。
(4)回收策略
当我们创建pod时如果使用pvc做为存储卷,那么它会和pv绑定,当删除pod,pvc和pv绑定就会解除,解除之后和pvc绑定的pv卷里的数据需要怎么处理,目前,卷可以保留,回收或删除:
1、Retain
当删除pvc的时候,pv仍然存在,处于released状态,但是它不能被其他pvc绑定使用,里面的数据还是存在的,当我们下次再使用的时候,数据还是存在的,这个是默认的回收策略。
2、Delete
删除pvc时即会从Kubernetes中移除PV,也会从相关的外部设施中删除存储资产。
4.4 创建pod,使用pvc作为持久化存储卷
1、创建nfs共享目录
#在宿主机创建NFS需要的共享目录
[root@hd1.com ~]# mkdir /data/volume_test/v{1,2,3,4,5,6,7,8,9,10} -p
#配置nfs共享宿主机上的/data/volume_test/v1..v10目录
[root@hd1.com ~]# cat /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v1 192.168.1.0/24(rw,no_root_squash)
注:下面v2-v10,与v1相同,只改动目录名,故此处忽略。
#重新加载配置,使配置成效
[root@hd1.com ~]# exportfs -ar
2.创建pv
[root@hd1.com ~]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: v1
spec:
capacity:
storage: 1Gi #pv的存储空间容量
accessModes: ["ReadWriteOnce"]
nfs:
path: /data/volume_test/v1 #把nfs的存储空间创建成pv
server: 192.168.1.11 #nfs服务器的地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v2
spec:
capacity:
storage: 2Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/volume_test/v2
server: 192.168.1.11
注:后面相同一直写v10,只改动名字、存储大小、路径。
#更新资源清单文件
[root@hd1.com ~]# kubectl apply -f pv.yaml
#查看pv资源
[root@hd1.com ~]# kubectl get pv
#STATUS是Available,表示pv是可用的
4、创建pvc,和符合条件的pv绑定
[root@hd1.com ~]# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 2Gi
#更新资源清单文件
[root@hd1.com ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/my-pvc created
#查看pv和pvc
[root@hd1.com ~]# kubectl get pv
#STATUS是Bound,表示这个pv已经被my-pvc绑定了
[root@hd1.com ~]# kubectl get pvc
pvc的名字-绑定到pv-绑定的是v2这个pv-pvc可使用的容量是2G
5、创建pod,挂载pvc
[root@hd1 volume]# cat pod_pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-pvc
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nginx-html
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-html
persistentVolumeClaim:
claimName: my-pvc
#更新资源清单文件
[root@hd1.com ~]# kubectl apply -f pod_pvc.yaml
pod/pod-pvc created
#查看pod状态
[root@hd1.com ~]# kubectl get pods | grep pod-pvc
pod-pvc 1/1 Running 0 27s
#通过上面可以看到pod处于running状态,正常运行
#进入容器,写入index.html数据
[root@hd1 volume]# kubectl exec -it pod-pvc -- /bin/bash
root@pod-pvc:/# cd /usr/share/nginx/html/
root@pod-pvc:/usr/share/nginx/html# echo hello > index.html
#退出容器,访问一下nginx容器的首页内容
[root@hd1 volume]# curl 10.244.156.146
hello
#删除pod-pvc 这个pod,发现pvc还是存在的
root@hd1 ~]# kubectl delete pods pod-pvc
pod "pod-pvc" deleted
[root@hd1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound v2 2Gi RWX 2d21h
#删除pvc
[root@hd1 ~]# kubectl delete pvc my-pvc
persistentvolumeclaim "my-pvc" deleted
#发现pv的状态发生了变化
#此时我们进入到nfs的共享目录,发现我们建立的index.html还是存在的
[root@hd1 ~]# cd /data/volume_test/v2
[root@hd1 v2]# ls
index.html
注:使用pvc和pv的注意事项
1、我们每次创建pvc的时候,需要事先有划分好的pv,这样可能不方便,那么可以在创建pvc的时候直接动态创建一个pv这个存储类,pv事先是不存在的。
2、pvc和pv绑定,如果使用默认的回收策略retain,那么删除pvc之后,pv会处于released状态,我们想要继续使用这个pv,需要手动删除pv,kubectl delete pv pv_name,删除pv,不会删除pv里的数据,当我们重新创建pvc时还会和这个最匹配的pv绑定,数据还是原来数据,不会丢失。