(一) volumes
1.卷(volumes):
容器中的文件存在时间是短暂的,当一个容器发生崩溃时,文件会丢失,而容器重新启动后状态却是干净的;而第二个问题时解决了一个Pod中不同容器间共享文件。卷的类型有很多,详细请查看官方文档:https://kubernetes.io/zh/docs/concepts/storage/volumes/
[2.emptyDir]
2.1.emptyDir卷特性:
当Pod被创建时,emptyDir卷也随之创建,在Pod运行期间,此卷会一直存在。
用于Pod中不同容器间的数据共享。
当 Pod 从节点上删除时,emptyDir 卷中的数据也会被永久删除并不会保存。
emptyDir 卷存储在该节点所使用的介质可以是磁盘或 SSD 或网络存储也可以是内存;注意介质为内存的话会记入容器消耗。
2.2.官方示例:
配置项只有最后三行,相对比较简单。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
**2.3.我们做一个实例:
第一步:我们创建一个准备用的deploy类型的yaml文件,上面通用部分没贴,主要看我们要用的这部分,创建两个nginx容器,将emptyDir的卷分别挂在两个容器下。
kind: Deployment
metadata:
labels:
app: dp-nginx
name: dp-nginx
spec:
replicas: 1
selector:
matchLabels:
app: dp-nginx
strategy: {}
template:
metadata:
labels:
app: dp-nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /opt
name: share-volume
- image: redis
name: redis
volumeMounts:
- mountPath: /tmp
name: share-volume
volumes:
- name: share-volume
emptyDir: {}
第二步:执行yaml文件创建deploy资源
[root@k8s-master01 ~]# kubectl create -f dp-nginx.yaml
deployment.apps/dp-cm created
[root@k8s-master01 ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
dp-nginx 1/1 1 1 17m
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
dp-nginx-98db5f6df-6g24r 2/2 Running 0 2m40s
第三步:在nginx容器的/opt目录下创建一个文件,然后再redis容器内成都/tmp目录下查看,看是否共享
# 在nginx容器内创建文件
[root@k8s-master01 ~]# kubectl exec -ti dp-nginx-98db5f6df-6g24r -c nginx -- bash
root@dp-nginx-98db5f6df-6g24r:/# cd /opt/
root@dp-nginx-98db5f6df-6g24r:/opt# touch haha.txt
root@dp-nginx-98db5f6df-6g24r:/opt# ls
haha.txt
# 到redis容器查看是否文件共享
[root@k8s-master01 ~]# kubectl exec -ti dp-nginx-98db5f6df-6g24r -c redis -- ls /tmp
haha.txt
第四步:没有第四步了,从第三步可以看到在nginx容器创建的文件,是可以在redis容器内看到的,所有共享卷是成功的。
3.HostPath
3.1.HostPath卷特性:
hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。
注意:官方是不推荐使用这种方式的,但是当你需要使用hostPath时,它的范围应仅限于所需的文件或目录,并以只读方式挂载。
3.2.官方示例:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# 宿主上目录位置
path: /data
# 此字段为可选
type: Directory
hostPath类型支持的type值:
默认为空:意味着在安装 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate:如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory:在给定路径上必须存在的目录。
FileOrCreate:如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File:在给定路径上必须存在的文件。
Socket:在给定路径上必须存在的 UNIX 套接字。
CharDevice:在给定路径上必须存在的字符设备。
BlockDevice:BlockDevice
注意: FileOrCreate 模式不会负责创建文件的父目录。 如果欲挂载的文件的父目录不存在,Pod 启动会失败。
3.3.我们做一个实例:
我们的举例是用的File类型,你也可以尝试其他类型,配置方式都一样
第一步:从下面这个例子中可以看到容器内的时区与我们宿主机时区是不一样的
[root@k8s-master01 ~]# kubectl exec -ti dp-nginx-98db5f6df-6g24r -c nginx -- cat /etc/timezone
Etc/UTC
[root@k8s-master01 ~]# cat /etc/timezone
Asia/Shanghai
第二步:修改yaml文件,然后更新deploy副本
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /opt
name: share-volume
- mountPath: /etc/timezone
name: timezone
- image: redis
name: redis
volumeMounts:
- mountPath: /tmp
name: share-volume
volumes:
- name: share-volume
emptyDir: {}
- name: timezone
hostPath:
path: /etc/timezone # 宿主机路径
type: File
# 更新副本,注意大小写,我刚才file写的小写报错了
[root@k8s-master01 ~]# kubectl replace -f dp-nginx.yaml
deployment.apps/dp-nginx replaced
第三步:查看容器时区,是成功的,已经修改为shanghai;可以看到挂载宿主机时区的已经修改,没挂载的redis容器的时区还是默认
[root@k8s-master01 ~]# kubectl exec dp-nginx-7b456ccf45-8c8fn -c nginx -- cat /etc/timezone
Asia/Shanghai
[root@k8s-master01 ~]# kubectl exec dp-nginx-7b456ccf45-8c8fn -c redis -- cat /etc/timezone
Etc/UTC
4.nfs
nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。但是生产中不大建议使用。
第一步:准备一台NFS服务器,创建共享目录/data/test
第二步:将nfs的共享目录挂载到Pod中
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /opt
name: nfs-volume
volumes:
- name: nfs-volume
nfs:
server: 192.168.10.10 # nfs服务器ip
path: /data/test
第三步:创建Pod资源后在容器内部/opt下创建文件,在nfs服务器/data/test下查看是否共享,反过来测试也可以。如果资源共享说明成功。
其他类型的卷可以查看官网,下一篇写pv与pvc!
(二) PV&PVC(持久化存储)
1.PV与PVC
PV:持久卷(PersistentVolume)简称PV,是集群中的一块存储,可以由管理员事先供应。可以配置NFS、Ceph等常用存储配置,相对于volumes,提供了更多的功能,如生命周期管理、大小的限制。
PV 卷的供应有两种方式:静态供应或动态供应。
静态:
集群管理员预先创建许多PV,在PV的定义中能够体现存储资源的特性。
动态:
集群管理员无须预先创建PV,而是通过StorageClass的设置对后端存储资源进行描述,标记存储的类型和特性。用户通过创建PVC对存储类型进行申请,系统将自动完成PV的创建及与PVC的绑定。如果PVC声明的Class为空"",则说明PVC不使用动态模式。
PVC:持久卷申领(PersistentVolumeClaim,PVC)表达的是用户对存储的请求。就像Pod消耗Node的资源一样,PVC消耗PV资源。PVC可以申请存储空间的大小(size)和访问模式。
由管理员创建PV连接到后端存储,使用人员或管理员创建PVC使用PV资源。
2.PV资源回收
当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除,从而允许该资源被回收再利用。PV对象的回收策略告诉集群,当其被从申领中释放时如何处理该数据卷。目前,数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)。
Retain:保留资源
保留策略可以管理员手动回收资源,当PVC被删除后,PV仍然存在,对应的数据卷被视为"已释放(released)",管理员可以手动回收资源。
Delete:删除数据
需要插件支持,如果支持,那么删除PVC时也会自动删除PV和相关的后端存储资源;动态卷默认为delete。
Recycle:回收(弃用)
回收策略已被弃用,代替者为动态供应。如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的 擦除(rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。
3.访问模式
ReadWriteOnce:
卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷,缩写为RWO。
ReadOnlyMany:
卷可以被多个节点以只读方式挂载,缩写为ROX。
ReadWriteMany:
卷可以被多个节点以读写方式挂载,缩写为RWX。
ReadWriteOncePod:
卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本,缩写为RWOP。
注意: 你的存储支不支持这种访问模式,
具体情况查看:官方文档
https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#access-modes
4.存储分类
文件存储(Filesystem):
一些数据可能需要多个节点使用,比如用户头像、用户上传文件等,实现方式:NFS、NAS、FTP等;NFS和FTP不推荐。
块存储(block):
一些数据只能被一个节点使用,或者是一块裸盘整个挂载使用,比如数据库、redis等,实现方式是Ceph、GlusterFS、公有云等。
对象存储:
由程序代码直接实现的一种存储方式,云原生应用无状态化常用的实现方式;实现方式:一般是符合53标准的云存储,比如AWS的53存储、Minio等。
5.创建PV卷
列举两个实例,其他类型可参考官网
5.1.实例:创建NAS/NFS类型的PV
生产不推荐NFS。可以使用NAS。
准备一台NFS服务器
第一步:准备一台NFS服务器,我这个装的有点多,你也可以只安装nfs服务器
[root@localhost ~]# yum -y install nfs* rpcbind
第二步:所有节点安装nfs客户端,不然不能识别,每一个需要挂载nfs的节点都需要装
[root@k8s-master01 ~]# yum -y install nfs-utils
第三步:在服务端创建共享目录
[root@localhost ~]# mkdir -p /data/k8s
第四步:服务端配置共享目录
[root@localhost ~]# cat /etc/exports
/data/k8s/ *(rw,sync,no_subtree_check,no_root_squash)
[root@localhost ~]# exportfs -r
[root@localhost ~]# systemctl restart nfs rpcbind
第五步:有另外一台机器挂载共享目录测试是否成功
[root@k8s-master01 hgfs]# mount -t nfs 192.168.10.6:/data/k8s /mnt
[root@k8s-master01 mnt]# mkdir hah
[root@k8s-master01 mnt]# ls
111.txt hah
# 在nfs服务端查看
[root@localhost k8s]# ls
111.txt hah
创建一个PV
第一步:编写一个PV的yaml文件
apiVersion: v1
kind: **PersistentVolume**
metadata:
name: pv-nfs
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs-slow
nfs:
path: /data/k8s
server: 192.168.10.6
对上面的yaml文件做一下说明:
通用的开头就不说了
capacity:容量配置,这个pv使用多大容量,当然需要后端存储支持才行
volumeMode:卷的模式,目录4有说明
accessModes:PV的访问模式,目录3有说明
accessClassName:PV的类,特定的PV只能绑定特定的PVC
persistentVolumeReclaimPolicy:回收策略,目录2有说明
nfs:NFS服务配置,里面包含共享目录和服务端IP
第二步:执行yaml文件创建此PV;注意PV的成功跟后端存储正不正常没什么关系。
[root@k8s-master01 ~]# kubectl create -f pv-nfs.yaml
persistentvolume/pv-nfs created
[root@k8s-master01 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 2Gi RWO Recycle Available nfs-slow 54s
第三步:说一下PV的状态(STATUS)
Available:可用,没有被PVC绑定的空闲资源
Bound:已绑定,已经被PVC绑定
Released:已释放,PVC被删除,资源未被重新使用
Failed:失败,自动回收失败
5.2.实例:创建一个hostPath类型的PV
当你没有一个可靠的存储,但是数据又不能丢失,可以挂载到宿主机的路径,即使重启数据还在。
第一步:创建一个pv-host.yaml文件
apiVersion: v1
kind: PersistentVolume
metadata:
name: host-pv-volume
labels:
type: local
spec:
storageClassName: hostpath
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data" # 宿主机路径
第二步:执行yaml文件创建PV
[root@k8s-master01 ~]# kubectl create -f pv-host.yaml
persistentvolume/host-pv-volume created
[root@k8s-master01 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
host-pv-volume 1Gi RWO Retain Available hostpath 9s
pv-nfs 2Gi RWO Recycle Available nfs-slow
6.PVC
6.1.Pod与PVC与PV的关系
上图说一下PV与PVC的绑定,Pod又是怎么挂载PVC
首先创建一个PV,它的名字是pv-nfs,storageClassName名字是nfs-slow(这个名字不唯一,就是说其他PV也可以叫这个名字)
然后创建一个PVC,它的名字是test-pv-claim,storageClassName名字是nfs-slow(PVC绑定PV也是根据这个名字判断,根据上一点说的特性也就是说一个PVC可以绑定多个storageClassName名字是nfs-slow的PV)注意PVC设置的资源大小要等于小于PV。
最后Pod使用的时候创建一个volumes,这个名字是test-pv-storage,这个volumes使用的PVC资源要写PVC的name,也就是test-pv-claim;等Pod中的容器挂载资源的时候挂载的名字是volumes的name,也就是test-pv-storage。
6.2.创建一个PVC挂载到Pod
注意:pvc要和Pod在同一个命名空间,而pv不需要;因为都是在默认空间,就没指定,需要注意。
第一步:编写一个PVC的yaml文件
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pv-claim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi # 小于等于pv
storageClassName: nfs-slow
第二步:执行yaml文件创建PVC;从下面这个状态来看已经绑定成功了,绑定了pv-nfs,类型为nfs-slow,都是前面指定的。
[root@k8s-master01 ~]# kubectl create -f pvc-nfs.yaml
persistentvolumeclaim/test-pv-claim created
[root@k8s-master01 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pv-claim Bound pv-nfs 2Gi RWO nfs-slow 20s
第三步:创建Pod挂载PVC
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: dp-nginx
name: dp-nginx
spec:
replicas: 1
selector:
matchLabels:
app: dp-nginx
strategy: {}
template:
metadata:
labels:
app: dp-nginx
spec:
volumes:
- name: test-pv-storage
persistentVolumeClaim:
claimName: test-pv-claim
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: test-pv-storage
第四步:创建Pod,进入Pod查看挂载情况
[root@k8s-master01 ~]# kubectl replace -f dp-nginx.yaml
deployment.apps/dp-nginx replaced
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
dp-nginx-fcd88d6f8-prxcd 1/1 Running 0 22s
[root@k8s-master01 ~]# kubectl exec -ti dp-nginx-fcd88d6f8-prxcd -- bash
root@dp-nginx-fcd88d6f8-prxcd:/# df -Th
Filesystem Type Size Used Avail Use% Mounted on
overlay overlay 17G 5.2G 12G 31% /
tmpfs tmpfs 64M 0 64M 0% /dev
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
shm tmpfs 64M 0 64M 0% /dev/shm
/dev/mapper/centos-root xfs 17G 5.2G 12G 31% /etc/hosts
192.168.10.6:/data/k8s nfs4 17G 2.4G 15G 14% /usr/share/nginx/html
tmpfs tmpfs 3.8G 12K 3.8G 1% /run/secrets/kubernetes.io/serviceaccount
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/acpi
tmpfs tmpfs 2.0G 0 2.0G 0% /proc/scsi
tmpfs tmpfs 2.0G 0 2.0G 0% /sys/firmware
# 可以看到10.6的共享目录已经挂载到了/nginx/html下
第五步:测试,在nfs服务器共享目录下创建资源,进入Pod容器内查看是否存在
# nfs服务器中创建资源
[root@localhost k8s]# ls
111.txt hah
# 在Pod的nginx容器中查看
root@dp-nginx-fcd88d6f8-prxcd:/# cd /usr/share/nginx/html/
root@dp-nginx-fcd88d6f8-prxcd:/usr/share/nginx/html# ls
111.txt hah
# 内容存在,说明创建成功
网友评论