一、简介
当在 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: v1kind: Podmetadata:name: emptydirlabels:app: emptyDirspec:containers:- name: emptyimage: nginximagePullPolicy: IfNotPresentvolumeMounts:- name: cachemountPath: /cachevolumes:- emptyDir: {}name: cache测试:#查看调度到了那台机器上kubectl get pods -owide#查看pod的uidkubectl 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/shkubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.# cd cache# lsaa#在pod创建bb目录mkdir bb在宿主机查看[root@lx110 cache]# lsaa bb删除pod查看是否目录被清空kubectl delete pods emptydir[root@lx110 cache]# ls[root@lx110 cache]#
2.hostPath
vim hostPath.yaml---apiVersion: v1kind: Podmetadata:name: hostpathspec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentvolumeMounts:- name: hostpathmountPath: /cache-nginx- name: tomcatimage: docker.io/library/tomcat:latestimagePullPolicy: IfNotPresentvolumeMounts:- name: hostpathmountPath: /cache-tomcatvolumes:- name: hostpathhostPath:path: /datatype: DirectoryOrCreate测试:#查看调度到了那台机器kubectl get pods -owide#在宿主机目录上创建cc目录mkdir /data/cc登录到pod上kubectl exec -it hostpath -c tomcat /bin/shkubectl 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 -pvmkdir: created directory '/data'mkdir: created directory '/data/volumes'systemctl start nfs-servervim /etc/exports/data/volumes *(rw,no_root_squash)exportfs -arvsystemctl restart nfs-serversystemctl enable nfs-server其余节点安装nfs节点驱动yum install nfs-utils -ysystemctl start nfs-server测试连接192.168.1.100/data/volumesshowmount -e 192.168.1.100挂载mount -t nfs 192.168.1.100:/data/volumes /data2/手动卸载umount /data22、编写yaml文件vim nfs.yaml---apiVersion: v1kind: Podmetadata:name: nfsspec:containers:- name: test-nfsimage: nginximagePullPolicy: IfNotPresentports:- containerPort: 80protocol: TCPvolumeMounts:- name: nfs-volumesmountPath: /usr/share/nginx/htmlvolumes:- name: nfs-volumesnfs:path: /data/volumesserver: 192.168.1.1003、测试echo "123" >> /data/volumes/index.htmlkubectl get pods -owideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbusybox-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:80123
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 -arvexporting *:/data/volume_test/v2exporting *:/data/volume_test/v1exporting *:/data/volumes2、创建pv---apiVersion: v1kind: PersistentVolumemetadata:name: testpv1labels:app: v1spec:capacity:storage: 1GiaccessModes: ["ReadWriteOnce"] #单路读写,只允许一个pod去读写nfs:path: /data/volume_test/v1server: 192.168.1.100---apiVersion: v1kind: PersistentVolumemetadata:name: testpv2labels:app: v2spec:capacity:storage: 2GiaccessModes: ["ReadWriteMany"] #多路读写,允许多个pod读写nfs:path: /data/volume_test/v2server: 192.168.1.100查看pvkubectl get pv --show-labels #状态为Available为可用状态3、创建PVC---apiVersion: v1kind: PersistentVolumeClaimmetadata:name: testpvclabels:app: v1spec:selector:matchLabels:app: v1accessModes: ["ReadWriteOnce"]resources:requests:storage: 1Gi测试:[root@lx100 test]# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEtestpv1 1Gi RWO Retain Bound default/testpvc 10mtestpv2 2Gi RWX Retain Available 10m[root@lx100 test]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtestpvc Bound testpv1 1Gi RWO 35s创建Pod挂载pvc---apiVersion: v1kind: Podmetadata:name: pvctest1spec:containers:- name: nginximage: nginximagePullPolicy: IfNotPresentvolumeMounts:- name: pvcmountPath: /usr/share/nginx/htmlvolumes:- persistentVolumeClaim:claimName: testpvcname: pvc测试#查看pod信息kubectl get pods -owideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbusybox-6bb56cf754-sx2dt 1/1 Running 9 (41m ago) 4d1h 10.247.66.155 lx120hostpath 2/2 Running 0 175m 10.246.71.98 lx110nfs 1/1 Running 0 71m 10.247.66.157 lx120pvctest1 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.1582355555
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需要的SAvim serviceaccount.yaml---apiVersion: v1kind: ServiceAccountmetadata:name: nfs-provisioner#对sa授权kubectl create clusterrolebinding nfs-provisioner --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner#安装nfs-provisioner程序mkdir /data/nfs_pro -pvim /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 -arvvim nfs-deployment.yaml---kind: DeploymentapiVersion: apps/v1metadata:name: nfs-provisionerspec:selector:matchLabels:app: nfs-provisionerreplicas: 1strategy:type: Recreatetemplate:metadata:labels:app: nfs-provisionerspec:serviceAccount: nfs-provisionercontainers:- name: nfs-provisionerimage: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0imagePullPolicy: IfNotPresentvolumeMounts:- name: nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAMEvalue: example.com/nfs- name: NFS_SERVERvalue: 192.168.1.20- name: NFS_PATHvalue: /data/nfs_provolumes:- name: nfs-client-rootnfs:server: 192.168.1.20path: /data/nfs_pro#创建storageclass,动态供给PVvim nfs-storageclass.yaml---apiVersion: storage.k8s.io/v1kind: StorageClassmetadata:name: nfsprovisioner: example.com/nfs #应该与上面deployment文件中的env- name: PROVISIONER_NAME值一致kubectl apply -f nfs-storageclass.yaml#查看storageclass是否被创建kubectl get scNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGEnfs example.com/nfs Delete Immediate false 14mvim claim.yaml---kind: PersistentVolumeClaimapiVersion: v1metadata:name: test-claim1spec:accessModes: ["ReadWriteMany"]resources:requests:storage: 1GistorageClassName: nfs[root@lx20 k8s]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtest-claim1 Bound pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b 1Gi RWX nfs 13mvim read-pod.yaml---kind: PodapiVersion: v1metadata:name: podtestpvcspec:containers:- name: podimage: nginximagePullPolicy: IfNotPresentvolumeMounts:- name: nfs-pvcmountPath: /usr/share/nginx/htmlrestartPolicy: "Never"volumes:- name: nfs-pvcpersistentVolumeClaim:claimName: test-claim1kubectl get podsecho liangxi >> /data/nfs_pro/default-test-claim1-pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b/index.htmlkubectl get pods -owidecurl http://10.243.166.13liangxi#查看详细信息kubectl describe pod podtestpvcVolumes:nfs-pvc:Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)ClaimName: test-claim1ReadOnly: false
