Kubernetes 存储入门

目录

Volume 的概念

Volume 的类型

通过 emptyDir 共享数据

编写 emptyDir 的 Deployment 文件

部署该 Deployment

查看部署结果

登录 Pod 中的第一个容器

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

删除此 Pod

使用 HostPath 挂载宿主机文件

编写 Deployment 文件,实现 HostPath 挂载

创建此 Pod

查看创建结果

测试挂载情况

删除

挂载 NFS 至容器

安装 NFS

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

开启 nfs(在 NFS 服务器上)

编写 Deployment 文件,挂载 NFS

部署此 Pod

查看部署结果

登录容器查看挂载结果

PesistentVolume(PV,持久卷)

 PV 回收策略

PV 访问策略

PV 的配置方式

基于 NFS 的 PV

(1) 提前安装好 nfs 服务

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

备注

PersistentVolumeClaim(PVC,持久卷声明)

PVC 的创建

(1) 为 hostpath 类型的 PV 创建 PVC

(2) 为 NFS 类型的 PV 创建 PVC

 PVC 的使用

(1)创建pod,绑定hostpath的PV

(2)创建pod。绑定NFS的PV

Volume 的概念

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

我们应该把有状态的应用变成无状态的应用,意思是指把数据从应用中剥离出来,把产生的数据文件或者缓存的信息都放在云端,比如常用的 NFS(生产环境中不建议使用,因为存在单点故障,推荐使用分布式的存储或者公有云的 NAS 服务 )、Ceph、GlusterFS、Minio 等。

在传统的架构中,如果要使用这些存储,需要提前在宿主机挂载,然后程序才能访问,在实际使用时,经常碰到新加节点忘记挂载存储导致的一系列问题。而 Kubernetes 在设计之初就考虑了这些问题,并抽象出 Volume 的概念用于解决数据存储的问题。

在容器中的磁盘文件是短暂的,当容器崩溃时,Kubectl 会重新启动容器,但是容器运行时产生的数据文件都会丢失,之后容器会以干净的状态启动。另外,当一个 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 为 {} 即可

编写 emptyDir 的 Deployment 文件

[root@k8s-master ~]# cat <<EOF>nginx-empty.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: 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 与 volumes 说明
    • 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 的内存限制中。

部署该 Deployment

[root@k8s-master ~]# kubectl create -f nginx-empty.yaml

查看部署结果

[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6ffffd7c7b-jrw7f   2/2     Running   0          10s

登录 Pod 中的第一个容器

[root@k8s-master ~]# kubectl exec -ti nginx-6ffffd7c7b-jrw7f -c nginx01 -- sh

备注:

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

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

[root@k8s-master ~]# kubectl exec -ti nginx-6ffffd7c7b-jrw7f -c nginx02 -- sh

注意
登录仿处后,此处可以使用 date 命令查看容器中的时间,会发现时间是不对的。是因为时区的问题,容器内使用的不是亚洲 / 上海市区。导致时间不对。

删除此 Pod

[root@k8s-master ~]# kubectl delete -f nginx-empty.yaml

使用 HostPath 挂载宿主机文件

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

编写 Deployment 文件,实现 HostPath 挂载

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

[root@k8s-master ~]# cat <<EOF>nginx-hostPath.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: /etc/localtimename: timezone-timevolumes:- name: timezone-timehostPath:path: /etc/localtimetype: File
EOF

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

创建此 Pod

[root@k8s-master ~]# kubectl create -f nginx-hostPath.yaml

查看创建结果

[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-5c9b77966c-jrw7f   1/1     Running   0          47m

测试挂载情况

[root@k8s-master ~]# kubectl exec -ti nginx-5c9b77966c-jrw7f -c nginx -- sh
# date

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

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

删除

[root@k8s-master ~]# kubectl delete -f nginx-hostPath.yaml

挂载 NFS 至容器

安装 NFS

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

在所有的 Kubernetes 节点都要安装

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

[root@k8s-master ~]# mkdir /opt/wwwroot
[root@k8s-master ~]# echo "This is my test file">/opt/wwwroot/index.html
[root@k8s-master ~]# vim /etc/exports
/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)

开启 nfs(在 NFS 服务器上)

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

编写 Deployment 文件,挂载 NFS

[root@k8s-master ~]# cat <<EOF>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
EOF

部署此 Pod

[root@k8s-master ~]# kubectl create -f nginx-nfsVolume.yaml

查看部署结果

[root@k8s-master ~]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
nginx-fbd47c4c-izscp     1/1     Running   0          8m15s

登录容器查看挂载结果

[root@k8s-master ~]# kubectl exec -ti nginx-fbd47c4c-izscp -c nginx -- bash

PesistentVolume(PV,持久卷)

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

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

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

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

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

 PV 回收策略

当用户使用完卷时,可以从 API 中删除 PVC 对象,从而允许回收资源。回收策略会告诉 PV 如何处理该卷。目前回收策略可以设置为 Retain、Recycle 和 Delete。静态 PV 默认的为 Retain,动态 PV 默认 为 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、OpenStack Cinder 等。

PV 访问策略

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

  • ReadWriteOnce:单路可读写,可以被单节点以读写模式挂载,命令行中可以被缩写为 RWO。
  • ReadOnlyMany:多路只读,可以被多节点以只读模式挂载,命令行中可以被缩写为 ROX。
  • ReadWriteMany:多路可读写,可以被多个节点以读写模式挂载,命令行中可以被缩写为 RWX。
  • ReadWriteOncePod:单节点只读(1.22+ ),只能被一个 Pod 以读写的模式挂载,命令行中可以被缩写为 RWOP。

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

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

PV 的配置方式

[root@k8s-master ~]# cat <<EOF>hostpath-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:name: mypv-hostpathlabels:type: local
spec:storageClassName: pv-hostpathcapacity:storage: 10GiaccessModes:- ReadWriteOncehostPath:path: "/mnt/data"
EOF

备注:

  • hostPath:宿主机的路径,使用 hostPath 类型需要固定 Pod 所在的节点,防止 Pod 漂移造成数据丢失。
  • storageClassName 是一个用于标识 StorageClass 对象名称的标签。当你创建或配置 PersistentVolumeClaim(PVC )时,可以指定 storageClassName 来告诉 Kubernetes 你希望使用哪个 StorageClass 来配置存储。
[root@k8s-master ~]# kubectl create -f hostpath-pv.yaml
[root@k8s-master ~]# kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available           pv-hostpath             5s

基于 NFS 的 PV

(1) 提前安装好 nfs 服务

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

# 客户端安装 nfs-utils
yum -y install nfs-utils# 创建共享目录
mkdir /opt/wwwroot
# 写入测试文件
echo "This is my test file">/opt/wwwroot/index.html
# 编辑 exports 文件配置共享规则
vim /etc/exports
/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)
systemctl start nfs
systemctl start rpcbind

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

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

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

备注

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

创建 PV

[root@k8s-master ~]# kubectl create -f nfs-pv.yaml

查看PV创建结果

[root@k8s-master ~]# kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM        STORAGECLASS   REASON   AGE
mypv-hostpath   10Gi       RWO            Retain           Available   pv-hostpath   pv-hostpath             76s
mypv-nfs        5Gi        RWO            Recycle          Available   pv-nfs        pv-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 绑定需满足前提:accessModesstorageClassNamevolumeMode 需相同,且 PVC 的 storage 需小于等于 PV 的 storage 配置。

PVC 的创建

(1) 为 hostpath 类型的 PV 创建 PVC
 

[root@k8s-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@k8s-master ~]# kubectl create -f pvc-hostpath.yaml
[root@k8s-master ~]# kubectl get pvc
NAME            STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    4s

(2) 为 NFS 类型的 PV 创建 PVC

[root@k8s-master ~]# cat pvc-nfs.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:name: mypvc-nfs
spec:storageClassName: pv-nfsaccessModes:- ReadWriteOnceresources:requests:storage: 3Gi

注意:

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

[root@k8s-master ~]# kubectl create -f pvc-nfs.yaml
[root@k8s-master ~]# kubectl get pvc
NAME            STATUS   VOLUME          CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc-hostpath   Bound    mypv-hostpath   10Gi       RWO            pv-hostpath    3m21s
mypvc-nfs        Bound    mypv-nfs        5Gi        RWO            pv-nfs         5s

 PVC 的使用

已创建 PV 并通过 PVC 绑定,若让程序使用存储,需将 PVC 挂载到 Pod。和之前挂载方式类似,通过 volumes 字段配置,使用 PVC 挂载时,只需写 PVC 名字,无需关心存储细节。即使非 Kubernetes 管理员、不懂存储的人员,也能简单配置使用。比如将之前创建的 hostPath 类型 PVC 挂载到 Pod,只需配置一个 PersistentVolumeClaim 类型的 volumesclaimName 配置为 PVC 名称即可。

(1)创建pod,绑定hostpath的PV

[root@k8s-master ~]# cat <<EOF>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
EOF

备注:

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

[root@k8s-master ~]# kubectl create -f pvc-pv-pod-hostpath.yaml
[root@k8s-master ~]# kubectl get pod -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP             NODE        NOMINATED NODE   READINESS GATES
hostpath-pv-pod   1/1     Running   0          111s   10.244.85.204   k8s-node01   <none>           <none>
# 进入 Node 节点的 PV 对应宿主路径
[root@k8s-node01 ~]# cd /mnt/data/
# 创建测试文件
[root@k8s-node01 data]# touch aaa.txt
# 进入 Pod 内部
[root@k8s-master ~]# kubectl exec -it hostpath-pv-pod -- bash
# 查看 PVC 挂载到 Pod 内的路径内容
root@hostpath-pv-pod:/# ls /usr/share/nginx/html/
aaa.txt

(2)创建pod。绑定NFS的PV

[root@k8s-master ~]# cat <<EOF>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
EOF

备注:

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

[root@k8s-master ~]# kubectl create -f pvc-pv-pod-nfs.yaml
[root@k8s-master ~]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
pvc-nfs   1/1     Running   0          4s
kubectl exec -it pvc-nfs -- bash
ls /usr/share/nginx/html/

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

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

相关文章

深入理解Redission释放锁过程

lock.unlock();调用unlock方法&#xff0c;往下追Override public void unlock() {try {// 1. 执行异步解锁操作并同步等待结果// - 获取当前线程ID作为锁持有者标识// - unlockAsync()触发Lua脚本执行实际解锁// - get()方法阻塞直到异步操作完成get(unlockAsync(Thread.curre…

四、计算机组成原理——第4章:指令系统

目录 4.1指令系统 4.1.1指令集体系结构 4.1.2指令的基本格式 1.零地址指令 2.一地址指令 3.二地址指令 4.三地址指令 5.四地址指令 4.1.3定长操作码指令格式 4.1.4扩展操作码指令格式 4.1.5指令的操作类型 1.数据传送 2.算术和逻辑运算 3.移位操作 4.转移操作 …

RAG面试内容整理-检索器与生成器的解耦架构

在RAG系统中,检索器(Retriever)与生成器(Generator)的解耦架构是实现灵活高效的关键设计。所谓解耦,即将检索相关文档和生成答案两个步骤分开,由不同的模块或模型负责。这种架构带来的直接好处是模块独立优化:我们可以针对检索任务微调或更换检索模型,而不必影响生成模…

【2026毕业论文鸿蒙系统毕设选题】最新颖的基于HarmonyOS鸿蒙毕业设计选题汇总易过的精品毕设项目分享(建议收藏)✅

文章目录前言最新毕设选题&#xff08;建议收藏起来&#xff09;最新颖的鸿蒙毕业设计选题汇总100套易过的精品毕设项目分享毕设作品推荐&#x1f447;&#x1f447;&#x1f447;文未可免费咨询毕设相关问题&#xff0c;点赞留言可送系统源码&#x1f447;&#x1f447;&#…

超全!Linux 面试 100 题精选解析:网络篇|16 个 Linux 网络排查与配置必考题详解

网络&#xff0c;是 Linux 系统的神经系统。 一台服务器再强大&#xff0c;没有网络连接也如孤岛。尤其在实际运维与面试场景中&#xff0c;“网络相关的问题”是高频重灾区&#xff0c;比如&#xff1a; IP 配置错乱&#xff0c;连不上公网DNS 无响应&#xff0c;域名解析失败…

在 CentOS 上安装 FFmpeg

在 CentOS 上安装 FFmpeg 可以通过以下两种推荐方法实现&#xff08;以 CentOS 7/8 为例&#xff09;&#xff1a; 方法一&#xff1a;通过 RPM Fusion 仓库安装&#xff08;推荐&#xff09; # 1. 安装 EPEL 仓库 sudo yum install epel-release# 2. 启用 RPM Fusion 仓库 # C…

数据结构——图(一、图的定义)

一、图的定义1、什么是图&#xff1f;图G(V,E) 如图&#xff0c;无向图G顶点集V{,,...,}&#xff0c;用|V|表示图G的顶点个数如&#xff1a;V{A,B,C,D} ,|V|4边集E{(u,v)|uV, vV}&#xff0c; 用|E|表示图G的边的条数如&#xff1a;E{(u,v)|(A,B),(A,D),(A,C),(C,D)}&#xf…

Python 列表推导式与生成器表达式

Python 列表推导式与生成器表达式在 Python 中&#xff0c;列表推导式&#xff08;List Comprehension&#xff09;和生成器表达式&#xff08;Generator Expression&#xff09;是处理序列数据的高效工具。它们不仅能简化代码&#xff0c;还能提升数据处理的效率。本文将详细介…

XCF32PVOG48C Xilinx Platform Flash PROM

XCF32PVOG48C 是 Xilinx 公司推出的一款高容量、低功耗的 Platform Flash PROM&#xff08;平台闪存配置芯片&#xff09;&#xff0c;专为 Xilinx FPGA 和 CPLD 系列产品提供非易失性配置存储支持。凭借其 32 Mbit 的大容量与出色的系统兼容性&#xff0c;该芯片成为中高端 FP…

重复文件清理工具,附免费链接

链接:https://pan.baidu.com/s/1s_Zx1eHp5Y-XnbbGldIgvw?pwdkjex 提取码:kjex 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦

【Spring Boot 快速入门】二、请求与响应

目录请求响应请求Postman 工具简单参数请求实体参数请求数组集合参数日期参数JSON 参数路径参数响应请求响应 请求 Postman 工具 Postman 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件 作用&#xff1a;常用于进行接口测试 简单参数请求 原始方式 在原始的…

高并发系统技术架构

&#xff08;点个赞&#xff0c;算法会给你推荐更多类似干货 ~&#xff09; 口诀&#xff1a; CDN 扛静态&#xff0c;WAF 防恶意&#xff1b;验证码拦机器&#xff1b; Nginx 先限流&#xff0c;Sentinel 再熔断&#xff1b; Redis 扣库存&#xff0c;MQ 异步写&#xff1b; 对…

python任意模块间采用全局字典来实现借用其他类对象的方法函数来完成任务或数据通信的功能

我们在编写pthon代码时&#xff0c;模块间的数据通信主要采用以下几种方法&#xff1a;1、采用全局变量。所有模块都通过引用全局变量&#xff0c;通过本模块对此全局变量数据的修改值&#xff0c;其他模块也能访问并得到此全局变量的当前值&#xff0c;由于全局变量的不可控性…

linux 部署 flink 1.15.1 并提交作业

下载 1.15.1 https://flink.apache.org/downloads.html#apache-flink-1151 部署模式分类 会话模式应用模式单作业模式 1、会话模式 先启动一个集群&#xff0c;保持一个会话&#xff0c;然后通过客户端提交作业&#xff0c;所有作业都在一个会话执行&#xff1b; 会话模式适合规…

Redis数据量过大的隐患:查询会变慢吗?如何避免?

一、Redis数据过多引发的五大隐患&#xff08;附系统交互图&#xff09; #mermaid-svg-X83bpHUu830QXKUt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-X83bpHUu830QXKUt .error-icon{fill:#552222;}#mermaid-svg-…

网络与信息安全有哪些岗位:(3)安全运维工程师

安全运维工程师是企业安全防线的 “日常守护者”&#xff0c;既要确保安全设备与系统的稳定运行&#xff0c;又要实时监控潜在威胁&#xff0c;快速响应并处置安全事件&#xff0c;是连接安全技术与业务运营的关键角色。其核心价值在于通过常态化运维&#xff0c;将安全风险控制…

鱼皮项目简易版 RPC 框架开发(三)

本文为笔者阅读鱼皮的项目 《简易版 RPC 框架开发》的笔记&#xff0c;如果有时间可以直接去看原文&#xff0c; 1. 简易版 RPC 框架开发 前面的内容可以笔者的前面两个篇笔记 鱼皮项目简易版 RPC 框架开发&#xff08;一&#xff09; 鱼皮项目简易版 RPC 框架开发&#xff08;…

嵌入式Linux:注册线程清理处理函数

在 Linux 多线程编程中&#xff0c;线程终止时可以执行特定的清理操作&#xff0c;通过注册线程清理函数&#xff08;thread cleanup handler&#xff09;来实现。这类似于使用 atexit() 注册进程终止处理函数。线程清理函数用于在线程退出时执行一些资源释放或清理工作&#x…

【Git】Linux-ubuntu 22.04 初步认识 -> 安装 -> 基础操作

文章目录Git 初识Git 安装Linux-centosLinux-ubuntuWindowsGit 基本操作配置 Git认识工作区、暂存区、版本库添加文件 -- 场景一查看 .git 文件添加文件 -- 场景二修改文件版本回退撤销修改情况一&#xff1a;对于工作区的代码&#xff0c;还没有 add情况二&#xff1a;已经 ad…

轻量级音乐元数据编辑器Metadata Remote

简介 什么是 Metadata Remote (mdrm) &#xff1f; Metadata Remote 是一个基于 Web 的音频元数据编辑工具&#xff0c;旨在简化在无头服务器&#xff08;即没有图形用户界面的服务器&#xff09;上编辑音频文件的元数据。用户只需使用 Docker 和浏览器&#xff0c;无需复杂的…