Kubernetes存储Volume

        数据是一个企业的发展核心,他涉及到数据存储和数据交换的内容。在生产环境中尤为重要的一部分,在 Kubernetes 中另一个重要的概念就是数据持久化 Volume。

一、Volume的概念

        对于大多数的项目而言,数据文件的存储是非常常见的需求,比如存储用户上传的头像、文件以及数据库的数据。在 Kubernetes 中,由于应用的部署具有高度的可扩展性和编排能力(不像传统架构部署在固定的位置),因此把数据存放在容器中是非常不可取的,这样也无法保障数据的安全。

        我们应该把有状态的应用变成无状态的应用,意思是指把数据从应用中剥离出来,把产生的数据文件或者宦岑的信息都放在云端,比如常用的NFS(生产环境中不建议使用,因为存在单点故障,推荐使用分布式的存储或者公有云的 NAS 服务)、ceph、GlusterFs、Minio 等。
        在传统的架构中,如果要使用这些存储,需要提前在宿主机挂载,然后程序才能访问,在实际使用时,经常碰到新加节点忘记挂载存储导致的一系列问题。而 Kubernetes 在设计之初就考虑了这些问题,并抽象出 Volume 的概念用于解决数据存储的问题。
        在容器中的磁盘文件是短暂的,当容器崩溃时,Kubect1 会重新启动容器,但是容器运行时产生的数据文件都会丢失,之后容器会以干净的状态启动。另外,当一个Pod 运行多个容器时,各个容器可能需要共享一些文件,诸如此类的需求都可以使用 Volume 解决。

        Docker 也有卷的概念,但是在 Docker 中,卷只是磁盘上或另一个容器中的目录,其生命周期不受管理。虽然 Docker 已经提供了卷驱动程序,但是功能非常有限,例如从 Docker1.7版本开始,每个容器只允许一个卷驱动程序,并且无法将一些特殊的参数传递给后端存储。
        另一方面,Kubernetes 卷具有明确的生命周期,与使用他的 Pod 相同,因此在 Kubernetes 中的卷可以比 Pod 中运行的任何容器的生命周期都长,并且可以在容器重启或者销毁之后保留数据。Kubernetes支持多种类型的卷,并且 Pod 可以同时使用任意数量的卷。

        从本质上讲,和虚拟机或者物理机一样,卷被挂载后,在容器中也只是一个目录,可能包含一些数据Pod 中的容器也可以对其进行增删改査操作,使用方式和裸机挂载几乎没有区别。要使用卷也非常简单,和其他参数类似,Pod 只需要通过.spec.volumes 字段指定为Pod 提供的卷,然后在容器中配置块,使用.spec.containers.volumeMounts字段指定卷的挂载目录即可。

二、Volume的类型

        在传统架构中,企业内可能有自己的存储平台,比如 NFS、Ceph、GlusterFs、Minio 等。如果所在的环境在公有云,也可以使用公有云提供的 NAS、对象存储等。在 Kubernetes 中,Volume 也支持配置这些存储,用于挂载到 Pod 中实现数据的持久化。Kubernetes Volume 支持的卷的类型有很多。

以下为常见的卷:

  • CephFS
  • GlusterFs
  • ISCSI
  • Cinder
  • NFS
  • RBD
  • HostPath

当然也支持一些 Kubernetes 独有的类型:

  • ConfigMap:用于存储配置文件
  • Secret:用于存储敏感数据
  • EmptyDir:用于一个 Pod 内多个容器的数据共享
  • PersistentVolumeclaim:对PersistentVolume的申请

三、通过emptyDir共享数据

        emptyDir 是一个特殊的 Volume 类型,与上述 Volume 不同的是,如果删除 Pod,EmptyDir 卷中的数据也将被删除,所以一般 emptyDir 用于 Pod 中不同容器共享数据,比如一个 Pod 存在两个容器A和容器 B,容器A需要使用容器B产生的数据,此时可以采用 emptyDir 共享数据,类似的使用如 Filebeat收集容器内程序产生的日志。
        使用 emptyDir 卷时,直接指定 emptyDir 为{}即可

1.编写emptyDir 的 Deployment 文件

vim nginx-empty.yamlapiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx01volumeMounts:- mountPath: /optname: share-volume- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginx02command:- sh- -c- sleep 3600volumeMounts:- mountPath: /mntname: share-volumevolumes:- name: share-volumeemptyDir: {}#medium: Memory

备注:
volumeMounts:
   -  mountPath: /mnt
      name: share-volume##容器定义部分的卷挂载名称,此处的名称引用了 volumes 对应的名称
volumes :
        -name:share-volume        ##共享存储卷的名称
此案例会将 nginx01 中/opt 中的数据,共享给 nginx02 中的/mnt 日录

        此部署文件创建一个 Deployment,采用 spec.volume 字段配置了一个名字为 share-volume、类型为 emptyDir 的 volume,同时里面包含两个容器 nginx01和 nginx02,并将该 volume 挂载到了/opt 和/mnt 目录下,此时/opt 和/mnt 目录的数据就实现了共享。
        默认情况下,emptyDir 支持节点上的任何介质,可以使 SSD、磁盘或是网络存储,具体取决于自身环境。可以将 emptyDir.medium 字段设置为 Memory,让 Kubernetes 使用 tmpfs(内存支持的文件系统),虽然 tmpfs 非常快,但是在节点重启时,数据同样会被清除,并且设置的大小会被记入 Container 的内存限制中。

2.部署该 Deployment

[root@master ~]# ku create -f nginx-empty.yaml 
deployment.apps/nginx created

3.查看部署结果

[root@master ~]# ku get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-8f8dcfd8c-l57qg   2/2     Running   0          22s

4.登录Pod中的第一个容器

[root@master ~]# ku exec -it nginx-8f8dcfd8c-l57qg -c nginx01 -- bash
root@nginx-8f8dcfd8c-l57qg:/# cd /opt/
root@nginx-8f8dcfd8c-l57qg:/opt# touch aa
root@nginx-8f8dcfd8c-l57qg:/opt# touch bb
root@nginx-8f8dcfd8c-l57qg:/opt# touch cc
root@nginx-8f8dcfd8c-l57qg:/opt# exit
exit

备注:
在该容器中的/opt 下创建一个文件,并到第二个容器中査看,是否是共享的目录

5.登录第 Pod 中的第二个容器查看/mnt 下的文件

[root@master ~]# ku exec -it nginx-8f8dcfd8c-l57qg -c nginx02 -- bash
root@nginx-8f8dcfd8c-l57qg:/# cd /mnt/
root@nginx-8f8dcfd8c-l57qg:/mnt# ls
aa  bb	cc

6.删除此Pod

[root@master ~]# ku delete -f nginx-empty.yaml 
deployment.apps "nginx" deleted

四、使用 HostPath 挂载宿主机文件

        HostPath 卷可以将节点上的文件或目录挂载到 Pod 上,用于实现 Pod 和宿主机之间的数据共享,常用的示例有挂载宿主机的时区至 Pod,或者将 Pod 的日志文件挂载到宿主机等。

1.编写 Deployment 文件,实现 HostPath 挂载

以下为使用 HostPath 卷的示例,实现将主机的/etc/localtime 文件挂载到 Pod 的/etc/localtime

 vim nginx-hostPath.yamlapiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginxvolumeMounts:- mountPath: /etc/localtimename: timezone-timevolumes:- name: timezone-timehostPath:path: /etc/localtimetype: File

备注:
关于时区的设置
通过配置/etc/localtime 文件设置系统的时区/etc/localtime用于配置系统时区(此文件是一个链接文件,!链接自/usr/share/zoneinfo/Asia/Shanghai)

2.创建此 Pod

[root@master ~]# ku create -f nginx-hostPath.yaml 
deployment.apps/nginx created

3.查看创建结果

[root@master ~]# ku get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-59f95c99b5-jt7x9   1/1     Running   0          54s

4.测试挂载情况

[root@master ~]# ku exec -it nginx-59f95c99b5-jt7x9 -- bash
root@nginx-59f95c99b5-jt7x9:/# date
Mon Aug 26 09:31:25 CST 2024

在配置 HostPath 时,有一个 type 参数,用于表达不同的挂载类型,HostPath 卷常用的类型有:

  • type 为空字符串:默认选项,在挂载 HostPath 卷之前不会有任何检査
  • Directoryorcreate:如果给定的 path 不存在任何东西,那么将根据需要创建一个权限为 0755 的空目录,和 kubelet 具有相同的组和权限
  • Directory:目录必须存在于给定的路径下
  • FileorCreate:如果给定的路径不存在任何内容,则会根据需要创建一个空文件,权限设置为 8644,和 kubelet 具有相同的组和所有权
  • File:文件,必须存在于给定的路径中
  • Socket:UNIX套接字,必须存在于给定的路径中
  • CharDevice:字符设备,必须存在于给定的路径中
  • BlockDevice:块设备,必须存在于给定的路径中

5.删除

[root@master ~]# ku delete -f nginx-hostPath.yaml 
deployment.apps "nginx" deleted

五、挂载NFS至容器

1.安装NFS

在所有的Kubernets节点都要安装

[root@master ~]# yum -y install nfs-utils

2.设置共享目录(在NFS服务器上)

[root@k8s-master ~]# mkdir /opt/wwwroot
[root@k8s-master ~]# echo "This is my test file">/opt/wwwroot/index.html

3.开启 nfs(在 NFS 服务器上)

[root@master ~]# systemctl start nfs
[root@master ~]# systemctl start rpcbind

4.编写 Deployment 文件,挂载 NFS

 vim nginx-nfsVolume.yaml apiVersion: apps/v1
kind: Deployment
metadata:labels:app: nginxname: nginxnamespace: default
spec:replicas: 1selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginxvolumeMounts:- mountPath: /usr/share/nginx/htmlname: nfs-volumevolumes:- name: nfs-volumenfs:server: 192.168.10.101path: /opt/wwwroot

5.部署此Pod

[root@master ~]# ku create -f nginx-nfsVolume.yaml 
deployment.apps/nginx created

6.查看部署结果

[root@master ~]# ku get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7bf6df4679-nx8j2   1/1     Running   0          6s

7.登录容器查看挂载结果

[root@master ~]# ku exec -it nginx-7bf6df4679-nx8j2  -c nginx -- bash
root@nginx-7bf6df4679-nx8j2:/# cat index.html
cat: index.html: No such file or directory
root@nginx-7bf6df4679-nx8j2:/# cd /usr/share/nginx/html/
root@nginx-7bf6df4679-nx8j2:/usr/share/nginx/html# cat index.html
This is my test file

六、PersistentVolume(PV,持久卷)

虽然 volume 已经可以接入大部分存储后端,但是实际使用时还有诸多的问题。比如:

  • 当某个数据卷不再被挂载使用时,里面的数据如何处理?
  • 如果想要实现只读挂载,要如何处理?
  • 如果想要只能有一个 Pod 挂载,要如何处理?

        如上所述,对于很多复杂的需求,volume 可能难以实现,并且无法对存储的生命周期进行管理。另一个很大的问题是,在企业内使用 kubernetes 的不仅仅是 kubernetes 管理员,可能还有开发人员、测试人员以及初学 kubernetes 的技术人员,对于 kubernetes 的 volume 或者相关存储平台的配置参数并不了解,所以无法自行完成存储的配置。

        为此,kubernetes 引入了两个新的 API 资源:PersistentVolume(持久卷,简称 PV)和PersistentVolumeclaim(持久卷声明,简称PVC)。

        PV 是 kubernetes 管理员设置的存储,PVC是对 PV的请求,标识需要什么类型的 PV。他们同样是集群中的一类资源,但其生命周期比较独立,管理员可以单独对 PV 进行增删改査,不受 Pod 的影响,生命周期可能比挂载它的其他资源还要长。如果一个 kubernetes 集群的使用者并非只有 kubernetes 管理员那么可以通过提前创建 PV,用以解决对存储概念不是很了解的技术人员对存储的需求。和单独配置 volume类似,PV 也可以使用 NFS、GFS、CEPH 等常见的存储后端,并且可以提供更为高级的配置,比如访问模式、空间大小以及回收策略等。目前 PV的提供方式有两种:静态或动态。静态 PV 由管理员提前创建,动态PV 无需提前创建。

1.PV 回收策略

        当用户使用完卷时,可以从 API 中删除 PVC 对象,从而允许回收资源。回收策略会告诉 PV 如何处理改卷。目前回收策略可以设置为 Retain、Recycle 和 Delete。默认的为 delete

  • Retain:保留,该策略允许手动回收资源,当删除 PVC 时,PV仍然存在,PV 中的数据也存在。volume被视为已释放,管理员可以手动回收卷。
  • Recycle:回收,如果 volume 插件支持,Recycle 策略会对卷执行rm -rf 清理该 PV,卷中的数据已经没了,但卷还在,使其可用于下一个新的 PVC,但是本策略将会被弃用,目前只有 NFS 和 HostPath支持该策略。
  • Delete:删除,如果 volume 插件支持,删除 PVC 时会同时删除 PV,PV 中的数据自然也就没了。动态卷默认为 Delete,目前支持 Delete 的存储后端包括 AWS EBS、GCE PD、Azure Disk、OpenstackCinder 等。

2.PV 访问策略

        在实际使用 PV 时,可能针对不同的应用会有不同的访问策略,比如某类 Pod 可以读写,某类 Pod 只能读,或者需要配置是否可以被多个不同的 Pod 同时读写等,此时可以使用 PV 的访问策略进行简单控制,目前支持的访问策略如下:

  • Readwrite0nce:单路可读可写,可以被单节点以读写模式挂载,命令行中可以被缩写橙
  • RWO.ReadonlyMany:多路只读,可以被多节点以只读模式挂载,命令行中可以被缩写为
  • ROX.ReadwriteMany:多路可读可写,可以被多个节点以读写模式挂载,命令行中可以被缩写为 RWX。
  • Readwrite0ncePod:单节点只读(1.22+),只能被一个 Pod 以读写的模式挂载,命令行中可以被缩写为 RWOP。
    • Readwriteonce:表示具有读写权限,但是只能被一个node 挂载一次
    • ReadonlyMany:表示具有只读权限,可以被多个node 多次挂载
    • ReadwriteMany:表示具有读写权限,可以被多个node 多次挂载
    • Readwrite0ncePod:表示具有读写权限,只能被一个 Pod 挂载

        虽然 PV在创建时可以指定不同的访问策略,但是也要后端的存储支持才行。比如一般情况下,大部分块存储是不支持 ReadwriteMany 的。

        在企业内,可能存储很多不同类型的存储,比如 NFS、Ceph、GlusterFs等,针对不同类型的后端存储具有不同的配置方式,这也是对集群管理员的一种挑战,因为集群管理员需要对每种存储都要有所了解。

3.PV 的配置方式

(1)静态配置

        静态配置是手动创建 PV 并定义其属性,例如容量、访问模式、存储后端等。在这种情况下,Kubernetes管理员负责管理和配置 PV,然后应用程序可以使用这些 PV。静态配置通常用于一些固定的存储后端,如NFS.

(2)动态配置

        动态配置允许 Kubernetes 集群根据 PVC 的需求自动创建 PV,在这种情况下,管理员只需为存储后端配置 storageclass,然后应用程序就可以通过 PVC 请求存储。Kubernetes 将自动创建与 PVC 匹配的PV,并将其绑定到 PVC上。这种方法使得存储管理更加灵活和可扩展,允许管理员在集群中动态添加、删除、和管理存储资源

4.基于HostPath 的 PV

        可以创建一个基于 HostPath 的 PV,和配置 NFS 的PV 类似,只需要配置 hostPath 字段即可,其它配置基本一致。

(1)在所有 node 节点创建主机目录
[root@master ~]# mkdir /mnt/data
(2)编辑hostpath的yaml文件 
[root@master ~]# vim hostpath-pv.yaml kind: PersistentVolume
apiVersion: v1
metadata:name: mypv-hostpathlabels:type: local
spec:storageClassName: pv-hostpathcapacity:storage: 10GiaccessModes:- ReadWriteOncehostPath:path: "/mnt/data"

备注:
hostPath:宿主机的路径
使用 hostPath 类型需要固定 Pod 所在的节点,防止 Pod 漂移造成数据丢失。

[root@master ~]# ku create -f hostpath-pv.yaml 
persistentvolume/mypv-hostpath created
[root@master ~]# ku get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available           pv-hostpath             5s

5.基于NFS的pv

(1)提前安装好 nfs 服务

可以使用上一个案例中安装好的 NFS。或重新安装一台,步骤如下:
提前安装好 nfs 服务,192.168.10.101是 nfs 服务器,也可以是任意一台提供了 NFS 服务的主机客户端需要在所有的 Kubernetes 节点安装

(2)创建一个基于 NFS 的 PV

        PV 目前没有 NameSpace 隔离,不需要指定命名空间,在任意命名空间下创建的 PV 均可以在其他NameSpace 使用

[root@master ~]# vim nfs-pv.yaml apiVersion: v1
kind: PersistentVolume
metadata:name: mypv-nfs
spec:capacity:storage: 5GivolumeMode: FilesystemaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RecyclestorageClassName: pvc-nfsmountOptions:- hard- nfsvers=4.1nfs:path: /opt/wwwroot/server: 192.168.10.101

备注:

  • capacity:容量配置
  • volumeMode:卷的模式,目前支持 Filesystem(文件系统)和 Block(块),其中 Block 类型需要后端存储支持,默认为文件系统
  • accessModes:该PV的访问模式
  • storageclassName:Pv 的类,一个特定类型的PV 只能绑定到特定类别的 PVC
  • persistentVolumeReclaimPolicy:收策略
  • mountoption:非必要,新版本中已经弃用
  • nfs:NFS 服务配置,包括以下两个选项
    • path:NFS 上的共享目录

    • server:NFs的IP地址

创建PV:

[root@master ~]# ku create -f nfs-pv.yaml 
persistentvolume/mypv-nfs created

查看PV创建结果:

[root@master ~]# ku get pv
NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available           pv-hostpath             4m22s
mypv-nfs        5Gi        RWO            Recycle          Available           pvc-nfs                 4s

七、PersistentVolumeclaim(PVc,持久卷声明)

        当 kubernetes 管理员提前创建好了 PV,我们又应该如何使用它呢?
        这里介绍 kubernetes 的另一个概念 PersistentVolumeclaim(简称PVC)。PVC 是其他技术人员在 kubernetes 上对存储的申请,他可以标明一个程序需要用到什么样的后端存储、多大的空间以及什么访问模式进行挂载。这一点和 Pod 的 Qos 配置类似,Pod 消耗节点资源,PVC 消耗 PV 资源,Pod 可以请求特定级别的资源(CPU和内存),PVC可以请求特定的大小和访问模式的PV。例如申请一个大小为5G且只能被一个 Pod 只读访问的存储。
        在实际使用时,虽然用户通过 PVC获取存储支持,但是用户可能需要具有不同性质的 PV 来解决不同的问题,比如使用 SSD 硬盘来提高性能。所以集群管理员需要根据不同的存储后端来提供各种 PV,而不仅仅是大小和访问模式的区别,并且无须让用户了解这些卷的具体实现方式和存储类型,打扫了存储的解耦,降低了存储使用的复杂度。
        接下来我们来看看如何让 PVC 和前面创建的 PV 绑定。PVC和 PV进行绑定的前提条件是一些参数必须匹配,比如 accessModes、storageclassName、volumeMode 都需要相同,并且 PVc 的 storage 需要小于等于 PV 的 storage 配置。

1.PVC 的创建

(1)为 hostpath 类型的 PV 创建 PVC
[root@master ~]# vim pvc-hostpath.yaml kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: mypvc-hostpath
spec:storageClassName: pv-hostpathaccessModes:- ReadWriteOnceresources:requests:storage: 3Gi

注意:
        storageClassName:存储类名称需要和对应的 PV 中的名称一致,PV 和 PVC 进行绑定并非是名字相同,而是 StorageclassName 相同且其他参数一致才可以进行绑定

[root@master ~]# ku create -f pvc-hostpath.yaml 
persistentvolumeclaim/mypvc-hostpath created
[root@master ~]# ku get pvc
NAME             STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    9s
(2)为NFS类型的PV创建PVC
[root@master ~]# vim pvc-nfs.yaml kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: mypvc-nfs
spec:storageClassName: pvc-nfsaccessModes:- ReadWriteOnceresources:requests:storage: 3Gi

注意:
storageclassName:存储类名称需要和对应的 PV 中的名称一致 

[root@master ~]# ku create -f pvc-nfs.yaml 
persistentvolumeclaim/mypvc-nfs created
[root@master ~]# ku get pvc
NAME             STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    23m
mypvc-nfs        Bound    mypv-nfs        5Gi        RWO            pvc-nfs        18s

        从上述两个简单的例子可以看出,PVC的定义和后端存储并没有关系。对于有存储需求的技术人员,直接定义 PVC即可绑定一块 PV,之后就可以供 Pod使用,而不用去关心具体的实现细节大大降低了存储的复杂度。接下来我们看一下 PVC 如何提供给 Pod 使用。

2.PVC的使用

        上述创建了PV,并使用 PVC与其绑定,现在还差一步就能让程序使用这块存储,那就是将 PVC 挂载到 Pod。和之前的挂载方式类似,PVC 的挂载也是通过 volumes 字段进行配置的,只不过之前需要根据不同的存储后端填写很多复杂的参数’而使用 PVC进行挂载时,只填写 PVC的名字即可,不需要再关心任何的存储细节,这样即使不是 Kubemetes 管理员,不懂存储的其他技术人员想要使用存储,也可以非常简单地进行配置和使用。比如我们将之前创建的 hostPath 类型的 PVC 挂载到 Pod 中,可以看到只需要配置-个PersistentVolumeclaim 类型的 volumes,claimName 配置为 PVC 的名称即可:

(1)创建 pod,绑定 hostpath 的PV
[root@master ~]# vim pvc-pv-pod-hostpath.yaml kind: Pod
apiVersion: v1
metadata:name: hostpath-pv-pod
spec:volumes:- name: task-pv-storagepersistentVolumeClaim:claimName: mypvc-hostpathcontainers:- name: task-pv-containerimage: nginx:1.7.9ports:- containerPort: 80name: "http-server"volumeMounts:- mountPath: "/usr/share/nginx/html"name: task-pv-storage

备注:
claimName: mypvc-hostpath 是基于 hastpath 创建的 PVC 的名字

(2)创建 pod,绑定 NFS 的 PV
[root@master ~]# ku create -f pvc-pv-pod-hostpath.yaml 
pod/hostpath-pv-pod created
[root@master ~]# ku get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
hostpath-pv-pod          1/1     Running   0          3m11s   10.244.166.136   node1   <none>           <none>
nginx-7bf6df4679-nx8j2   1/1     Running   0          60m     10.244.104.9     node2   <none>           <none>
[root@master ~]# ku exec -it hostpath-pv-pod -- bash
root@hostpath-pv-pod:/# cd /usr/share/nginx/html/
root@hostpath-pv-pod:/usr/share/nginx/html# ls
aa  bb	cc
[root@node1 ~]# cd /mnt/data/
[root@node1 data]# touch aa
[root@node1 data]# touch bb
[root@node1 data]# touch cc
[root@master ~]# vim pvc-pv-pod-nfs.yaml kind: Pod
apiVersion: v1
metadata:name: pvc-nfs
spec:volumes:- name: pvc-nfs01persistentVolumeClaim:claimName: mypvc-nfscontainers:- name: task-pv-containerimage: nginx:1.7.9ports:- containerPort: 80name: "http-server"volumeMounts:- mountPath: "/usr/share/nginx/html"name: pvc-nfs01

 备注:

claimName:mypvc-nfs 是基于NFS创建的PVC的名字

[root@master ~]# ku create -f pvc-pv-pod-nfs.yaml 
pod/pvc-nfs created
[root@master ~]# ku get pod
NAME                     READY   STATUS    RESTARTS   AGE
hostpath-pv-pod          1/1     Running   0          10m
nginx-7bf6df4679-nx8j2   1/1     Running   0          68m
pvc-nfs                  1/1     Running   0          4s
[root@master ~]# ku exec -it pvc-nfs -- bash
root@pvc-nfs:/# cd /usr/share/nginx/html/
root@pvc-nfs:/usr/share/nginx/html# ls
index.html
root@pvc-nfs:/usr/share/nginx/html# touch aa
root@pvc-nfs:/usr/share/nginx/html# exit
exit
[root@master ~]# cd /opt/wwwroot/
[root@master wwwroot]# ls
aa  index.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/411478.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型低显存推理优化-Offload技术

近两年大模型火出天际&#xff1b;同时&#xff0c;也诞生了大量针对大模型的优化技术。本系列将针对一些常见大模型优化技术进行讲解。 [大模型推理优化技术-KV Cache][大模型推理服务调度优化技术-Continuous batching]大模型显存优化技术-PagedAttention大模型低显存推理优…

爬虫入门学习

流程 获取网页内容 HTTP请求 Python Requests解析网页内容 HTML网页结构 Python Beautiful Soup储存或分析数据 HTTP (Hypertext Transfer Protocol) 客户端和服务器之间的请求-响应协议 Get方法&#xff1a;获得数据 POST方法&#xff1a;创建数据 HTTP请求 请求行 方法类型…

零基础国产GD32单片机编程入门(二)GPIO输入中断含源码

文章目录 一.概要二.可嵌套的向量中断控制器 (NVIC)三.中断向量表四.中断优先级详解五.GD32外部中断控制器(EXTI)1.EXTI简介2.EXTI在中断向量表的位置3.EXTI外部中断产生的信号流向4.EXTI中断产生后的中断服务程序 六.GPIO输入中断的例程实验七.工程源代码下载八.小结 一.概要 …

Django+vue自动化测试平台(29)--测试平台集成playwright录制pytest文件执行

需求背景 一、 系统目标与功能概述 脚本管理: 系统需要能够组织和存储所有通过playwright官方插件录制的脚本。这包括脚本的上传、编辑、删除和版本控制功能。 脚本执行: 用户应该能够在后台界面上查看所有可用的脚本&#xff0c;并能够通过简单的点击操作来启动特定脚本的执…

Visual Basic 6.0教程/Visual Basic从入门到实践/Visual Basic学习视频教程

Visual Basic 6.0教程/Visual Basic从入门到实践/Visual Basic学习视频教程 李天生VB从入门到精通 第一章 VisualBasic6基本介绍 第二章 VisualBasic6的数据类型与运算符表达式 第三章 VisualBasic6的内部函数 第四章 VisualBasic6的基本语句 第五章 VisualBasic6的数组 第六章…

RX 8000系显卡规格曝光,全系GDDR6纯过渡产品

原文转载修改自&#xff08;更多互联网新闻/搞机小知识&#xff09;&#xff1a; RX 8000系显卡规格首曝&#xff0c;GDDR6显存就很骨感 前天&#xff0c;我们刚刚聊过有过新一代RTX 50系消息&#xff0c;虽然是按部就班地升级&#xff0c;但好在也是在升级。50系换核心升级显…

Sentinel熔断与限流

一、服务雪崩与解决方案 1.1、服务雪崩问题 一句话&#xff1a;微服务之间相互调用&#xff0c;因为调用链中的一个服务故障&#xff0c;引起整个链路都无法访问的情况。 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。 如图…

RabbitMQ 集群与高可用性

目录 单节点与集群部署 1.1. 单节点部署 1.2. 集群部署 镜像队列 1.定义与工作原理 2. 配置镜像队列 3.应用场景 4. 优缺点 5. Java 示例 分布式部署 1. 分布式部署的主要目标 2. 典型架构设计 3. RabbitMQ 分布式部署的关键技术 4. 部署策略和实践 5. 分布式部署…

前端开发学习Docker记录01镜像操作

Docker相关命令 Demo安装nginx 先搜索然后拉取&#xff0c;然后查看images列表是不是拉取成功 docker search nginxdocker pull nginx特定某个版本&#xff0c;镜像名&#xff1a;版本号 docker images

layui2.9 树组件默认无法修改节点图标,修改过程记录下

官方文档树组件 data 参数值&#xff0c;未提供icon属性配置 需要修改源码 layui.js, 搜索图片中标记部分 查找到之后&#xff0c;修改为 <i class“‘(i.icon || “layui-icon layui-icon-file”)’”> 如图&#xff1a; 修改完成后&#xff0c;即可在data中添加icon…

redis学习笔记 ——redis中的四大特殊数据结构

一.前言 在之前的学习中&#xff0c;我们已经介绍了Redis中常见的五种基本的数据结构&#xff0c;而今天我们就要开始介绍Redis的四种特殊的数据结构&#xff0c;它们分别是bitmap(位图)&#xff0c; HyperLogLog(基数统计),Geospatial(地理信息),Stream。 二.位图(Bitmap) …

Windows安装PostgreSQL数据库,保姆级教程

PostgreSQL 是客户端/服务器关系数据库管理系统 (RDMS)。PostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统&#xff08;RDBMS&#xff09;。PostgreSQL 也有自己的查询语言&#xff0c;称为 pgsql。 此外&#xff0c;PostgreSQL 还支持过程语言&a…

CS224W—07 Machine Learning with Heterogeneous Graphs

CS224W—07 Machine Learning with Heterogeneous Graphs 本节中&#xff0c;我们将学习如何在异构图中进行图神经网络学习。 Heterogeneous Graphs 图中的节点类型/边类型不同&#xff0c;就会形成一个异构图&#xff08;Heterogeneous Graph&#xff09;&#xff0c;例如下…

基于SpringBoot的在线答疑管理系统

基于SpringBootVue的在线答疑管理系统【附源码文档】、前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 摘要 基于SpringBoot的在线答疑管理系…

如何使用IDEA搭建Mybatis框架环境(详细教程)

文章目录 ☕前言为什么学习框架技术Mybatis框架简介 &#x1f379;一、如何配置Mybatis框架环境1.1下载需要MyBatis的jar文件1.2部署jar文件1.3创建MyBatis核心配置文件configuration.xml1.4.创建持久类(POJO)和SQL映射文件1.5.创建测试类 &#x1f9cb;二、 MyBatis框架的优缺…

Linux下UDP编程

一.概念介绍 1.socket 是什么&#xff1f; socket&#xff08;套接字&#xff09;本质上是一个抽象的概念&#xff0c;它是一组用于网络通信的 API&#xff0c;提供了一种统一的接口&#xff0c;使得应用程序可以通过网络进行通信。在不同的操作系统中&#xff0c;socket 的实…

【Python系列】Jinja2 模板引擎

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【软件测试】软件测试生命周期与Bug

目录 &#x1f4d5; 前言 &#x1f334;软件测试的生命周期 ​编辑&#x1f332;BUG &#x1f6a9; 概念 &#x1f6a9;描述bug的要素 &#x1f6a9;bug的级别 &#x1f6a9;bug的生命周期 &#x1f3c0;先检查自身&#xff0c;是否bug描述不清楚 &#x1f3c0;站在用…

Docker 安装 SqlServer

摘要&#xff1a;我们工作当中经常需要拉取多个数据库实例出来做集群&#xff0c;做测试也好&#xff0c;通过 Docker 拉取 SqlServer 镜像&#xff0c;再通过镜像运行多个容器&#xff0c;几分钟就可以创建多个实例&#xff0c;效率是相当的高。 1. docker 拉取镜像 注意&am…

[mysql]mysql的演示使用

mysql的演示使用 几个常见操作 1&#xff1a;show databases 这里第一个information_schema代表的是数据库的基本系统信息&#xff0c;数据库名称&#xff0c;表的名称&#xff0c;存储权限 第二个是mysql&#xff0c;保存的是我们数据库运行的时候需要的系统信息&#xff0…