一、简介
当在 Kubernetes 中部署应用程序时,数据通常存储在容器内部的文件系统中。然而,容器的生命周期是临时的,当容器被删除或重新启动时,容器内的数据也会丢失。为了解决这个问题,需要在 Kubernetes 中实现数据持久化。数据持久化是将数据保存到持久化存储介质(如磁盘)上,以便在容器被重新创建或迁移到其他节点时仍然可用。数据持久化的场景包括:
1、数据存储:许多应用程序需要保存用户生成的数据,如文件、图片、日志等。通过数据持久化,可以确保这些数据在容器销毁或重启后仍然存在。
2、数据共享:在某些情况下,多个容器或 Pod 可能需要访问和共享相同的数据。通过将数据存储在持久化卷中,可以使多个容器之间共享数据,实现数据一致性和共享访问。
3、数据备份和恢复:持久化存储解决方案通常提供数据备份和恢复机制,以防止数据丢失。这对于保护重要数据、应对故障或恢复到先前的状态非常重要。
4、数据迁移和扩展:在 Kubernetes 集群中,可能需要扩展应用程序到多个节点或迁移到其他集群。通过将数据存储在持久化卷中,可以方便地将数据与应用程序一起迁移到新的环境,无需担心数据丢失。
5、数据安全:某些行业或应用程序对数据的安全性有严格的要求。持久化存储解决方案通常提供数据加密和访问控制功能,以确保数据在传输和存储过程中的安全性。
二、存储卷简介
1、emptyDir
EmptyDir 卷的使用场景包括:
1. 临时文件共享:如果多个容器需要在同一个 Pod 中进行临时文件共享,EmptyDir 卷是一个简便的解决方案。容器可以将文件写入 EmptyDir 卷,并且其他容器可以读取和修改这些文件。当 Pod被删除或重启时,EmptyDir 卷中的文件会被清空。
2. 共享数据:某些应用程序可能需要在容器之间共享一些中间结果或临时数据。EmptyDir 卷可以作为容器之间的临时数据交换机制。容器可以将数据写入 EmptyDir 卷,其他容器可以读取和处理这些数据,从而实现数据共享和协作。
3. 缓存:EmptyDir 卷可以用作容器的缓存存储。某些应用程序可能需要将频繁访问的数据缓存到本地存储中,以提高性能。EmptyDir 卷提供了一个临时的、高速的存储介质来存储缓存数据,提供快速的读取和写入操作。
当在 Kubernetes 中使用存储卷(Volume),需要经历以下步骤:
1. 定义 Pod 的 Volume:在 Pod 的配置中定义一个 Volume,指定它要关联到哪个存储上。可以使用不同类型的 Volume,如 EmptyDir、HostPath、PersistentVolumeClaim 等,具体选择取决于需求。
2. 在容器中使用 Volume Mounts:在 Pod 的配置中,为每个容器定义 Volume Mounts,将Volume 挂载到容器内部的指定路径上。这样容器就能够访问和操作 Volume 中的数据。
3. 通过 Volume 实现数据持久化和共享:一旦 Volume 被挂载到容器中,容器就可以将数据写入Volume 或从 Volume 中读取数据。这使得数据能够在容器的生命周期内持久存在,并且可以被其他容器共享和访问。
2.hostPath(主机目录)
1. 直接访问主机文件系统:hostPath 卷允许容器直接访问主机节点上的文件系统。这对于需要访问主机节点上的特定文件或目录的应用程序非常有用。例如,某些日志收集器可能需要访问主机上的日志文件。
2. 主机依赖性:hostPath 卷的挂载是与特定主机节点紧密关联的,因此在调度 Pod 时需要特别注意。如果 Pod 被调度到另一个主机节点上,它将无法访问之前挂载的主机文件系统。
3. 危险性:hostPath 卷的使用需要谨慎,因为容器可以访问主机节点上的任何文件或目录,包括敏感的系统文件。此外,如果多个 Pod 使用相同的 hostPath 卷并且并发写入同一个文件,可能会导致冲突和数据损坏。
4. 开发和测试环境:hostPath 卷特别适用于开发和测试环境,因为它可以方便地将主机节点上的文件或目录映射到容器中,从而加快开发和测试工作流程。
3.NFS(远程目录)
1. 基本原理:NFS 允许将存储资源(文件或目录)通过网络共享给其他计算机。NFS 服务器将存储资源公开为共享,并将其挂载到客户端计算机上。客户端可以像访问本地文件系统一样访问这些共享资源。
2. 持久化存储方案:在 Kubernetes 中,NFS 可以作为持久化存储方案使用。它可以提供可靠的存储,并在 pod 被重新调度到不同的节点时保持数据的一致性。
3. 分布式访问:NFS 允许多个客户端同时访问共享资源。这使得它非常适合那些需要多个容器或Pod 共享数据的场景,例如数据库系统或分布式文件共享。
4. 跨平台兼容性:NFS 是一种跨平台的文件系统协议,支持在不同操作系统之间进行文件共享。这使得它成为在混合操作系统集群中实现持久化存储的理想选择。
5. 灵活性:NFS 提供了对存储资源的灵活访问和管理。管理员可以根据需求创建和配置 NFS 服务器,设置共享权限以及实施访问控制策略。
6. 备份和恢复:NFS 具备备份和恢复数据的能力。通过使用备份工具和策略,可以对 NFS 共享的数据进行定期备份,以防止数据丢失或损坏。
4.PVC
K8s PV 是什么?
K8s PVC 是什么?
K8s PVC 和 PV 工作原理
5.storangclass(存储类)
Kubernetes 提供了 StorageClass 来自动创建 PV,以减轻管理员的维护成本。以下是关于Kubernetes PV、PVC 和 StorageClass 的更新内容:
StorageClass 提供了以下好处:
三、实战
emptyDir(临时目录)
vim emptyDir.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: emptydir
labels:
app: emptyDir
spec:
containers:
- name: empty
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: cache
mountPath: /cache
volumes:
- emptyDir: {}
name: cache
测试:
#查看调度到了那台机器上
kubectl get pods -owide
#查看pod的uid
kubectl get pods -o yaml | grep uid
#登录到被调度到的节点
cd /var/lib/kubelet/pods/$uid/
cd volumes/kubernetes.io~empty-dir/cache/
在宿主机创建aa目录
mkdir aa
登录pod查看
kubectl exec -it emptydir /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# cd cache
# ls
aa
#
在pod创建bb目录
mkdir bb
在宿主机查看
[root@lx110 cache]# ls
aa bb
删除pod查看是否目录被清空
kubectl delete pods emptydir
[root@lx110 cache]# ls
[root@lx110 cache]#
2.hostPath
vim hostPath.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: hostpath
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: hostpath
mountPath: /cache-nginx
- name: tomcat
image: docker.io/library/tomcat:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: hostpath
mountPath: /cache-tomcat
volumes:
- name: hostpath
hostPath:
path: /data
type: DirectoryOrCreate
测试:
#查看调度到了那台机器
kubectl get pods -owide
#在宿主机目录上创建cc目录
mkdir /data/cc
登录到pod上
kubectl exec -it hostpath -c tomcat /bin/sh
kubectl exec -it hostpath -c nginx /bin/sh
查看/cache-tomcat和/cache-nginx和宿主机/data/目录下一样
type:
取值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate | 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。 |
Directory | 在给定路径上必须存在的目录。 |
FileOrCreate | 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。 |
File | 在给定路径上必须存在的文件。 |
Socket | 在给定路径上必须存在的 UNIX 套接字。 |
CharDevice | 在给定路径上必须存在的字符设备。 |
BlockDevice | 在给定路径上必须存在的块设备。 |
3.NFS
1、搭建NFS服务(控制节点)
yum install nfs-utils -y
#在宿主机创建 NFS 需要的共享目录
mkdir /data/volumes -pv
mkdir: created directory '/data'
mkdir: created directory '/data/volumes'
systemctl start nfs-server
vim /etc/exports
/data/volumes *(rw,no_root_squash)
exportfs -arv
systemctl restart nfs-server
systemctl enable nfs-server
其余节点安装nfs节点驱动
yum install nfs-utils -y
systemctl start nfs-server
测试连接192.168.1.100/data/volumes
showmount -e 192.168.1.100
挂载
mount -t nfs 192.168.1.100:/data/volumes /data2/
手动卸载
umount /data2
2、编写yaml文件
vim nfs.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: nfs
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.100
3、测试
echo "123" >> /data/volumes/index.html
kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox-6bb56cf754-sx2dt 1/1 Running 8 (30m ago) 4d 10.247.66.155 lx120 none> none>
hostpath 2/2 Running 0 104m 10.246.71.98 lx110 none> none>
nfs 1/1 Running 0 25s 10.247.66.157 lx120 none> none>
[root@lx100 test]# curl 10.247.66.157:80
123
4.PVC
静态配置
1、创建nfs共享目录
[root@lx100 test]# mkdir /data/volume_test/v{1,2} -p
[root@lx100 test]# vim /etc/exports
/data/volumes *(rw,no_root_squash)
/data/volume_test/v1 *(rw,no_root_squash)
/data/volume_test/v2 *(rw,no_root_squash)
[root@lx100 test]# exportfs -arv
exporting *:/data/volume_test/v2
exporting *:/data/volume_test/v1
exporting *:/data/volumes
2、创建pv
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: testpv1
labels:
app: v1
spec:
capacity:
storage: 1Gi
accessModes: ["ReadWriteOnce"] #单路读写,只允许一个pod去读写
nfs:
path: /data/volume_test/v1
server: 192.168.1.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: testpv2
labels:
app: v2
spec:
capacity:
storage: 2Gi
accessModes: ["ReadWriteMany"] #多路读写,允许多个pod读写
nfs:
path: /data/volume_test/v2
server: 192.168.1.100
查看pv
kubectl get pv --show-labels #状态为Available为可用状态
3、创建PVC
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: testpvc
labels:
app: v1
spec:
selector:
matchLabels:
app: v1
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
测试:
[root@lx100 test]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
testpv1 1Gi RWO Retain Bound default/testpvc 10m
testpv2 2Gi RWX Retain Available 10m
[root@lx100 test]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
testpvc Bound testpv1 1Gi RWO 35s
创建Pod挂载pvc
---
apiVersion: v1
kind: Pod
metadata:
name: pvctest1
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: pvc
mountPath: /usr/share/nginx/html
volumes:
- persistentVolumeClaim:
claimName: testpvc
name: pvc
测试
#查看pod信息
kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
busybox-6bb56cf754-sx2dt 1/1 Running 9 (41m ago) 4d1h 10.247.66.155 lx120
hostpath 2/2 Running 0 175m 10.246.71.98 lx110
nfs 1/1 Running 0 71m 10.247.66.157 lx120
pvctest1 1/1 Running 0 113s 10.247.66.158 lx120
[root@lx100 test]# echo 2355555 >> /data/volume_test/v1/index.html
[root@lx100 test]# curl 10.247.66.158
2355555
storangeclass(存储类)
安装nfs provisioner,用于配合存储类动态生成pv
参考:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
上传nfs-subdir-external-provisioner.tar.gz并导入镜像
ctr -n=k8s.io image import nfs-subdir-external-provisioner.tar.gz
#创建运行nfs-provisioner需要的SA
vim serviceaccount.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
#对sa授权
kubectl create clusterrolebinding nfs-provisioner --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner
#安装nfs-provisioner程序
mkdir /data/nfs_pro -p
vim /etc/exports
/data/volumes *(rw,no_root_squash)
/data/volume_test/v1 *(rw,no_root_squash)
/data/volume_test/v2 *(rw,no_root_squash)
/data/nfs_pro *(rw,no_root_squash)
exportfs -arv
vim nfs-deployment.yaml
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-provisioner
spec:
selector:
matchLabels:
app: nfs-provisioner
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-provisioner
image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: example.com/nfs
- name: NFS_SERVER
value: 192.168.1.20
- name: NFS_PATH
value: /data/nfs_pro
volumes:
- name: nfs-client-root
nfs:
server: 192.168.1.20
path: /data/nfs_pro
#创建storageclass,动态供给PV
vim nfs-storageclass.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs
provisioner: example.com/nfs #应该与上面deployment文件中的env- name: PROVISIONER_NAME值一致
kubectl apply -f nfs-storageclass.yaml
#查看storageclass是否被创建
kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs example.com/nfs Delete Immediate false 14m
vim claim.yaml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim1
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 1Gi
storageClassName: nfs
[root@lx20 k8s]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim1 Bound pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b 1Gi RWX nfs 13m
vim read-pod.yaml
---
kind: Pod
apiVersion: v1
metadata:
name: podtestpvc
spec:
containers:
- name: pod
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-pvc
mountPath: /usr/share/nginx/html
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim1
kubectl get pods
echo liangxi >> /data/nfs_pro/default-test-claim1-pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b/index.html
kubectl get pods -owide
curl http://10.243.166.13
liangxi
#查看详细信息
kubectl describe pod podtestpvc
Volumes:
nfs-pvc:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: test-claim1
ReadOnly: false