目录
1) NFS 在deployment/statefulset中直接使用
一:Volume 卷
容器中的文件在磁盘上是临时存放的,这给容器中运行的较重要的应用程序带来一些问题。
问题之一是当容器崩溃时文件丢失。 kubelet 会重新启动容器,但容器会以干净的状态重启。
问题之二会在同一 Pod
中运行多个容器并共享文件时出现。
所以K8S内部就出现了卷的概念,用来存储临时数据或者持久数据,更重要是用来解决持久数据存储问题。
二: 卷类型分类
1. 临时卷
1)为什么会有临时卷
有些应用程序需要额外的存储,但并不关心数据在重启后是否仍然可用,另有些应用程序需要以文件形式注入的只读数据,比如配置数据或密钥,临时卷 就是为此类用例设计的。因为卷会遵从 Pod 的生命周期,与 Pod 一起创建和删除, 所以停止和重新启动 Pod 时,不会受持久卷在何处可用的限制。
2)k8s临时卷类型
emptyDir Pod 启动时为空存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
configMap、 downwardAPI、 secret: 将不同类型的 Kubernetes 数据注入到 Pod 中
2. 持久卷
持久卷(PersistentVolume,PV是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)
制备(PV) ----> 绑定(PVC)----> 使用
3. 投射卷
一个 projected 卷可以将若干现有的卷源映射到同一个目录之上。
secret downwardAPI configMap serviceAccountToken
三:emptydir
当Pod分派到某个节点上时,emptyDir卷会被创建,并且Pod在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管Pod中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写emptyDir卷中相同的文件。 当Pod因为某些原因被从节点上删除时,emptyDir卷中的数据也会被永久删除.
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pd1
spec:
containers:
- image: busybox
name: emptydir-container
command:
- sh
- -c
- 'while true; do date >> /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
volumeMounts:
- mountPath: /mnt
name: cache-volume
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 500Mi
验证:
1)通过查看 /mnt/index.html 发现index.html 这个文件有内容
2)当我们删除这个pod
3)重新启动这个pod
4)查看/mnt/index.html文件里的内容从头开始
说明删除pod,挂载的文件也会跟着删除。
四:hostpath
hostPath卷能将主机节点文件系统上的文件或目录挂载到你的Pod中
使用hostPath需要注意未卷指定type
取值 | 行为 |
---|---|
空字符串 | 空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 |
DirectoryOrCreate | 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。 |
Directory | 在给定路径上必须存在的目录。 |
FileOrCreate | 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。 |
File | 在给定路径上必须存在的文件。 |
Socket | 在给定路径上必须存在的 UNIX 套接字。 |
CharDevice | 在给定路径上必须存在的字符设备。 |
BlockDevice | 在给定路径上必须存在的块设备。 |
apiVersion: v1
kind: Pod
metadata:
name: mydir-myfile-pd
spec:
containers:
- name: mydir-myfile
image: uhub.service.ucloud.cn/gfopshub/test-webserver:latest
volumeMounts:
- mountPath: /var/local/aaa
name: mydir
- mountPath: /var/local/aaa/1.txt
name: myfile
volumes:
- name: mydir
hostPath:
# 确保文件所在目录成功创建。
path: /var/local/aaa
type: DirectoryOrCreate
- name: myfile
hostPath:
path: /var/local/aaa/1.txt
type: FileOrCreate
1) 创建hostpath 挂载类型的pod
2)查看写入的信息
3)删除pod
4)验证之前写入的信息还存在不
通过截图可以看出,之前写入的信息还在,说明pod被删除后,之前创建的文件没有被删除。
五:NFS
nfs卷能将NFS(网络文件系统)挂载到你的Pod中。 不像emptyDir那样会在删除Pod的同时也会被删除,nfs卷的内容在删除Pod时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享
1) NFS 在deployment/statefulset
中直接使用
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
nfs:
path: /
#nas服务器地址
server: 10.1.131.111
nfs服务器的地址是 10.1.131.111 挂载的路径是 /usr/share/nginx/html
2) NFS服务器持久化存储
PV卷创建
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs
spec:
capacity:
storage: 1G
accessModes:
- ReadWriteMany
nfs:
server: 10.1.131.111
path: "/"
#挂载选项可选
# mountOptions:
# - nfsvers=4.2
[root@k8s-test-01 k8spv]# kubectl apply -f nfs-pv.yaml
persistentvolume/nfs created
[root@k8s-test-01 k8spv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs 1G RWX Retain Available 11s
创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 500Mi
volumeName: nfs
[root@k8s-test-01 k8spv]# kubectl apply -f nfs-pvc.yaml
persistentvolumeclaim/nfs created
[root@k8s-test-01 k8spv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs Bound nfs 1G RWX 13s
创建服务使用这个PVC
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-busybox
spec:
replicas: 3
selector:
matchLabels:
name: nfs-busybox
template:
metadata:
labels:
name: nfs-busybox
spec:
containers:
- image: busybox
command:
- sh
- -c
- 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'
imagePullPolicy: IfNotPresent
name: busybox
volumeMounts:
- name: nfs
mountPath: "/mnt"
volumes:
- name: nfs
persistentVolumeClaim:
claimName: nfs
验证下nfs挂载使用情况
[root@k8s-test-01 k8spv]# kubectl exec -it nfs-busybox-7b895df475-sfhx5 -- /bin/sh
/ #
/ # ls /mnt
index.html log
/ # cat /mnt/index.html
Sun May 7 07:31:41 UTC 2023
nfs-busybox-7b895df475-w44q2
#虽然pvc配置了容量大小,但看到的/mnt大小还是100G
/ # df -h
Filesystem Size Used Available Use% Mounted on
overlay 500.0G 4.4G 495.6G 1% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 15.7G 0 15.7G 0% /sys/fs/cgroup
10.1.131.111:/ 100.0G 0 100.0G 0% /mnt
/dev/sda1 500.0G 4.4G 495.6G 1% /etc/hosts
/dev/sda1 500.0G 4.4G 495.6G 1% /dev/termination-log
/dev/sda1 500.0G 4.4G 495.6G 1% /etc/hostname
/dev/sda1 500.0G 4.4G 495.6G 1% /etc/resolv.conf
shm 64.0M 0 64.0M 0% /dev/shm
tmpfs 31.0G 12.0K 31.0G 0% /var/run/secrets/kubernetes.io/serviceaccount
tmpfs 15.7G 0 15.7G 0% /proc/acpi
tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs 64.0M 0 64.0M 0% /proc/sched_debug
tmpfs 15.7G 0 15.7G 0% /proc/scsi
tmpfs 15.7G 0 15.7G 0% /sys/firmware
总结
从实际使用上讲使用nfs作为存储卷并不是一个好的方式,使用中会遇到千奇百怪的问题,kubernetes官方也不太推荐生产使用nfs提供存储卷,但是实际上有时候无可奈何的要去用,建议数据重要的服务使用分布式存储如ceph或者通过云厂商提供的csi挂载云盘作为存储卷,再不行就使用local pv.
参考:史上最全之K8s使用nfs作为存储卷的五种方式 · kubernetes
examples/staging/volumes/nfs at master · kubernetes/examples · GitHub