kubernetes-存储卷与持久化详解

背景

容器部署过程中一般有以下三种数据:
(1)启动时需要的初始数据,例如配置文件;
(2)启动过程中产生的临时数据,该临时数据需要多个容器间共享,例如类似于Redis的数据库;
(3)启动容器过程中产生的持久化数据,例如MySQL的数据目录(datadir);
所以,我们可以基于数据卷的方式实现数据的共享。

volume

介绍

在容器中的磁盘文件是短暂的,当容器崩溃时,Kubelet会重新启动容器,但容器运行时产生的数据文件都将会丢失,之后容器会以最干净的状态启动。另外,当一个Pod运行多个容器时,各个容器可能需要共享一些文件,诸如此类的需求都可以使用Volume解决。Pod只需要通过.spec.volumes字段指定为Pod提供的卷,然后在容器中配置块,使用.spec.containers.volumeMounts字段指定卷挂载的目录即可

在Kubernetes中,Volume也支持配置许多常用的存储,用于挂载到Pod中实现数据的持久化
Kubernetes Volume支持的卷的类型有很多,以下为常用的卷:
本地数据卷:
hostPath,emptyDir等。
网络数据卷:
NFS,Ceph,GlusterFS等。
公有云:
AWS,EBS等;
K8S资源:
configmap,secret等。
以上列举的是一些比较常用的类型,其他支持的类型可以查看Volume的官方文档
https://kubernetes.io/docs/concepts/storage/volumes/

emptyDir

emptyDir数据卷:

  • 是一个临时存储卷,与Pod生命周期绑定在一起,如果Pod删除了,这意味着数据卷也会被删除。

emptyDir的作用:

  • 可以实现持久化的功能;
  • 多个Pod之间不能通信数据,但是同一个Pod的多个容器是可以实现数据共享的;
  • 随着Pod的生命周期而存在,当我们删除Pod时,其数据也会被随之删除。

emptyDir的应用场景(同一个Pod中各个容器之间数据的共享):

  • 如Filebeat收集容器内程序产生的日志;
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行;

温馨提示:
使用emptyDir持久化数据时,删除容器并不会删除数据,因为容器删除并不能说明Pod被删除哟。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi

HostPath

hotsPath数据卷:

  • 挂载Node文件系统(Pod所在节点)上文件或者目录到Pod中的容器。
  • 如果Pod删除了,宿主机的数据并不会被删除,这一点是否感觉和咱们的数据卷有异曲同工之妙呢?

应用场景:

  • 常用的示例有挂载宿主机的时区至Pod,或者将Pod的日志文件挂载到宿主机等

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

  • type为空字符串:默认选项,意味着挂载hostPath卷之前不会执行任何检查
  • DirectoryOrCreate:如果给定的path不存在任何东西,那么将根据需要创建一个权限为0755的空目录,和Kubelet具有相同的组和权限
  • Directory:目录必须存在于给定的路径下
  • FileOrCreate:如果给定的路径不存储任何内容,则会根据需要创建一个空文件,权限设置为0644,和Kubelet具有相同的组和所有权
  • File:文件,必须存在于给定路径中
  • Socket:UNIX套接字,必须存在于给定路径中
  • CharDevice:字符设备,必须存在于给定路径中
  • BlockDevice:块设备,必须存在于给定路径中。
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-linux
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: example-container
    image: registry.k8s.io/test-webserver
    volumeMounts:
    - mountPath: /foo
      name: example-volume
      readOnly: true
  volumes:
  - name: example-volume
    # mount /data/foo, but only if that directory already exists
    hostPath:
      path: /data/foo # directory location on host
      type: Directory # this field is optional

NFS

和emptyDir、HostPath的配置方法类似,NFS的Volume配置也是在Volumes字段中配置的,和emptyDir不同的是,NFS属于持久化存储的一种,在Pod删除或者重启后,数据依旧会存储在NFS节点上。要使用nfs,k8s的node节点上需要安装好nfs客户端软件。

1.#全部安装nfs-utils
yum install -y nfs-utils


2.#创建共享目录
mkdir -p /data/kubernetes

3.#配置挂载点
[root@k8s151 pods]# cat /etc/exports
#k8s数据卷共享
/data/kubernetes  *(rw,no_root_squash)

4.#测试看看能不能用
showmount -e 10.0.0.151
mount -t nfs 10.0.0.151:/data/kubernetes  /mnt
df -h

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /my-nfs-data
      name: test-volume
  volumes:
  - name: test-volume
    nfs:
      server: my-nfs-server.example.com
      path: /my-nfs-volume
      readOnly: true

configMap

ConfigMap是用来存储配置文件的kubernetes资源对象,所有的配置内容都存储在etcd中。
创建ConfigMap的方式有4种:
通过直接在命令行中指定configmap参数创建,即--from-literal
通过指定文件创建,即将一个配置文件创建为一个ConfigMap--from-file=<文件>
通过指定目录创建,即将一个目录下的所有配置文件创建为一个ConfigMap,--from-file=<目录>
事先写好标准的configmap的yaml文件,然后kubectl create -f 创建
使用 YAML 文件定义 ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  key1: value1
  key2: value2

POD 引用 ConfigMap

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx
    env:
    - name: CONFIG_KEY
      valueFrom:
        configMapKeyRef:
          name: my-config
          key: key1
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
  volumes:
  - name: config-volume
    configMap:
      name: my-config

Secret

与ConfigMap类似,区别在于Secret主要存储铭感数据,所有的数据要经过base64编码。
但对于程序员而言,这依旧是明文数据,只不过想要拿到明文数据需要只需使用base64进行解码即可。
如下所示,基于base64进行编码和解码只需一行命令就搞定了。

[root@k8s-m1 ~]# echo -n "wfwkbgdqs$2e2f4" | base64
d2Z3a2JnZHFzZTJmNA==
[root@k8s-m1 ~]# echo -n "d2Z3a2JnZHFzZTJmNA==" | base64 -d
wfwkbgdqs$2e2f4

应用场景:
多用于存储凭据信息。
"kubectl create secret"支持常用的三种数据类型如下:(较ConfigMap支持的类型要多,我们可以理解ConfigMap支持的只是存储文本信息,对于存储仓库认证信息,TLS证书等ConfigMap均不支持,此时我们应该采用Secret哟~)
(1)docker-registry(kubernetes.io/dockerconfigjson):
存储镜像仓库认证信息。
(2)generic(Opaque):
存储密码,秘钥等。
(3)tls(kubernetes.io/tls):
存储TLS证书。
除了上面提到的几种类型,还有其它几种内置的数据类型(我从官网摘抄如下表所示),推荐阅读:
https://kubernetes.io/zh/docs/concepts/configuration/secret/

apiVersion: v1
kind: Secret
metadata:
  name: db-user-pass
type: Opaque  # 此处我们指定Secret资源的类型为"Opaque",通常用于存储密码,密钥等.
data:
  # 将编码后的值放到Secret资源的配置文件中
  username: YWRtaW4=
  password: eWluemhlbmdqaWU=

PersistentVolume

介绍

虽然volume实现了持久化存储,但是诸多高级特性还是无法实现。且没有生命周期的管理。在实际使用中volume面临的问题如下:

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

为此k8s引入了两个新的API资源:PersistentVolume和PersistentVolumeClaim。

  • PersistentVolume:属于k8s集群的全局资源,因此并不支持名称空间(namespace)。该资源对象本身并不负责数据的真实存储,而是负责和后端存储进行关联,每个pv都有提前定义好的存储能力。持久卷是对存储资源数据卷(volume)创建和使用的抽象,使得存储作为集群中的资源管理。这样我们就可以对数据卷的使用空间,读写权限做一个基本的权限管控,而不是放任Pod使用所有的数据卷资源。

  • PersistentVolumeClaim: 对PV的请求,表示需要什么类型的PV。和单独配置Volume类似,PV也可以使用NFS、GFS、CEPH等常用的存储后端,并且可以提供更加高级的配置,比如访问模式、空间大小以及回收策略等

目前PV的提供方式有两种:静态或动态。

  • 静态PV由管理员提前创建
  • 动态PV无须提前创建,由storageclass创建

PV回收策略

当用户使用完volume(pv本质上也是volume)时,可以删除PVC对象,从而通过回收策略回收pv资源。目前回收策略有以下三种。

  • Retain:保留,该策略允许手动回收资源,当删除PVC时,PV仍然存在,Volume被视为已释放,管理员可以手动回收卷。不指定回收策略默认为retain。
  • Recycle(k8s1.14版本开始已废弃):回收,如果Volume插件支持,Recycle策略会对卷执行rm -rf清理该PV,并使其可用于下一个新的PVC,目前只有NFS和HostPath支持该策略。
  • Delete:删除,如果Volume插件支持,删除PVC时会同时删除PV,动态卷默认为Delete,目前支持Delete的存储后端包括AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等。

对于 Kubernetes 1.29,仅nfs和hostPath卷类型支持回收。

PV访问策略

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

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

虽然PV在创建时可以指定不同的访问策略,但是也要后端的存储支持才行。比如一般情况下大部分块存储是不支持ReadWriteMany的,具体后端存储支持的访问模式可以参考
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

基于nfs或nas创建pv

[root@k8s-m1 ~]# cat pv-nfs.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs ##pv名
spec:
  capacity:
    storage: 5Gi ##pv的容量
  volumeMode: Filesystem ##卷的模式,目前支持Filesystem(文件系统) 和 Block(块),其中Block类型需要后端存储支持,默认为文件系统
  accessModes:
    - ReadWriteOnce  ##pv的访问模式
  persistentVolumeReclaimPolicy: Recycle ##pv的回收策略
  storageClassName: nfs-slow ##存储类型的名称,pvc通过该名字访问到pv
  nfs: ##pv的类型
    path: /data/nfs ##nfs服务器共享的目录
    server: 10.0.0.151 ##nfs服务器ip地址
[root@k8s-m1 ~]# kubectl create -f pv-nfs.yaml 
persistentvolume/pv-nfs created
[root@k8s-m1 ~]# kubectl get persistentvolume
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs   5Gi        RWO            Recycle          Available           nfs-slow                14s

创建hostpath类型的pv

一般不推荐使用该类型的pv,因为这种情况下使用的是宿主机的一个目录,pod和宿主机强绑定,不再具备高可用性。这种情况下需要利用污点,让pod和宿主机强绑定。

kind: PersistentVolume
apiVersion: v1
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: hostpath
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

PV的状态

  • Available:可用,没有被PVC绑定的空闲资源。
  • Bound:已绑定,已经被PVC绑定。
  • Released:已释放,PVC被删除,但是资源还未被重新使用。
  • Failed:失败,自动回收失败。

PersistentVolumeClaim

pv创建好了,如何使用呢,这时就需要用到pvc,pvc可以去申请pv资源。
pvc中定义了要使用的存储类型,存储空间大小以及存储的访问模式,例如申请一个大小为5Gi且只能被一个Pod只读访问的nfs存储。
下图是一个典型的pod使用pv作为volume的流程。

管理员创建pv,用户创建pvc和pv进行绑定,pod使用pvc申请到的pv资源作为volume来持久化存储数据。
image.png
那么pvc和pv是如何进行绑定的呢,主要依赖以下参数

参数 描述
Storageclass PV 与 PVC 的 storageclass 类名必须相同(或同时为空)。
AccessMode 主要定义 volume 的访问模式,PV 与 PVC 的 AccessMode 必须相同。
Size 主要定义 volume 的存储容量,PVC 中声明的容量必须小于等于 PV,如果存在多个满足条件的 PV,则选择最小的 PV 与 PVC 绑定。

pvc和pv绑定后,我们就可以通过在pod中使用pvc来申请pv资源了。只需要在pod的yaml文件中配置一个persistentVolumeClaim类型的volumes,claimName配置为PVC的名称即可
下面详细介绍下如何创建和使用pvc

创建pvc与pv进行绑定

[root@k8s-m1 ~]# cat pv-nfs.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs  
spec:
  capacity:
    storage: 5Gi    #pv的容量
  volumeMode: Filesystem    
  accessModes:
    - ReadWriteOnce     ##pv的访问模式
  persistentVolumeReclaimPolicy: Recycle    
  storageClassName: nfs-slow    ##存储类型的名称,pvc通过该名字访问到pv
  nfs:  
    path: /data/nfs 
    server: 10.0.0.151

创建pvc

[root@k8s-m1 ~]# cat nfs-pvc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-pvc-claim   ##pvc名
spec:
  storageClassName: nfs-slow    ##pv的类名
  accessModes:
    - ReadWriteOnce ##访问模式,和pv要一致
  resources:
    requests:
      storage: 3Gi  ##请求的容量大小,不能超过pv的大小

检查是否成功绑定

[root@k8s-m1 ~]# kubectl create -f pv-nfs.yaml
[root@k8s-m1 ~]# kubectl create -f nfs-pvc.yaml 
persistentvolumeclaim/nfs-pvc-claim created
[root@k8s-m1 ~]# 
[root@k8s-m1 ~]# kubectl get pvc
NAME            STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc-claim   Bound    pv-nfs   5Gi        RWO            nfs-slow       6s

使用pvc

pod绑定pvc,创建pod时pvc会自动去pv处申请资源作为pod的volume

[root@k8s-m1 ~]# cat pod-nfs-pvc.yaml 
kind: Pod
apiVersion: v1
metadata:
  name: nfs-pv-pod
spec:
  volumes:
    - name: nfs-pv-storage
      persistentVolumeClaim:
       claimName: nfs-pvc-claim  ##和pvc的名称一致
  containers:
    - name: nfs-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: nfs-pv-storage

检查pod是否成功挂载volume资源

[root@k8s-m1 ~]# kubectl create -f pod-nfs-pvc.yaml 
pod/nfs-pv-pod created
[root@k8s-m1 ~]# kubectl exec -it nfs-pv-pod -- bash
root@nfs-pv-pod:/# ls /usr/share/nginx/html/
root@nfs-pv-pod:/# df -h
Filesystem                Size  Used Avail Use% Mounted on
overlay                    39G   22G   18G  57% /
tmpfs                      64M     0   64M   0% /dev
tmpfs                     2.0G     0  2.0G   0% /sys/fs/cgroup
shm                        64M     0   64M   0% /dev/shm
/dev/vda2                  39G   22G   18G  57% /etc/hosts
172.18.102.233:/data/nfs   39G   22G   18G  57% /usr/share/nginx/html
tmpfs                     3.8G   12K  3.8G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                     2.0G     0  2.0G   0% /proc/acpi
tmpfs                     2.0G     0  2.0G   0% /proc/scsi
tmpfs                     2.0G     0  2.0G   0% /sys/firmware

动态存储storageclass

PV静态供给明显的缺点就是维护成本太高了,需要K8S运维人员手动创建一堆PV。
因此K8S开始支持PV动态供给,使用StorageClass对象实现,可以借助StorageClass提供的接口来自动创建PV。
每个storageclass都包含下面几个参数

  • provisioner:提供pv卷的存储类型
  • parameters:与后端存储对接时使用的参数,取决于provisioner中指定的存储。如ceph存储可以指定cluster id和pool id等。
  • reclaimPolicy:指定通过storageclass创建出来的pv的回收策略。可以是 Delete 或者 Retain。如果 StorageClass 对象被创建时没有指定 reclaimPolicy,它将默认为 Delete。
  • mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hard 和 nfsvers=4.1 等选项。

本次以NFS为例,要想使用NFS,我们需要一个nfs-client的自动装载程序,称之为provisioner,这个程序会使用我们已经配置好的NFS服务器自动创建持久卷,也就是自动帮我们创建PV

创建目录

mkdir /data && chmod -R 777 /data

nfs添加授权目录

cat /etc/exports
/data *(rw,sync,no_root_squash)

创建yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass                  #存储类的资源名称
metadata:
  name: nfs-storage                 #存储类的名称,自定义
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"        
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner         #存储分配器的名字,自定义
parameters:
  archiveOnDelete: "true"  ## 删除pv的时候,pv的内容是否要备份
reclaimPolicy: Retain
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  namespace: default
spec:
  replicas: 1                 #只运行一个副本应用
  strategy:                   #描述了如何用新的POD替换现有的POD
    type: Recreate            #Recreate表示重新创建Pod
  selector:        #选择后端Pod
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner          #创建账户
      containers:
        - name: nfs-client-provisioner         
          image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2      #使用NFS存储分配器的镜像,4.0.0以下不支持slelink
          imagePullPolicy: IfNotPresent
          # resources:
          #    limits:
          #      cpu: 10m
          #    requests:
          #      cpu: 10m
          volumeMounts:
            - name: nfs-client-root           #定义个存储卷,
              mountPath: /persistentvolumes   #表示挂载容器内部的路径
          env:
            - name: PROVISIONER_NAME          #定义存储分配器的名称
              value: k8s-sigs.io/nfs-subdir-external-provisioner         #需要和上面定义的保持名称一致
            - name: NFS_SERVER                                       #指定NFS服务器的地址,你需要改成你的NFS服务器的IP地址
              value: 10.0.0.151
            - name: NFS_PATH                                
              value: /data  ## nfs服务器共享的目录            #指定NFS服务器共享的目录
      volumes:
        - name: nfs-client-root           #存储卷的名称,和前面定义的保持一致
          nfs:
            server: 10.0.0.151            #NFS服务器的地址,和上面保持一致,这里需要改为你的IP地址
            path: /data       #NFS共享的存储目录,和上面保持一致
--- 
apiVersion: v1
kind: ServiceAccount                
metadata:
  name: nfs-client-provisioner       
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
[root@k8s-m1 ~]# kubectl apply -f nfs-sc.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
deployment.apps/nfs-provisioner-01 created
orageclass.storage.k8s.io/nfs-storage created

我们来基于StorageClass创建一个pvc,看看动态生成的pv是什么效果

[root@k8s-m1 ~]# vim pvc-sc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-sc
spec:
  storageClassName: nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi
      # kubectl  apply -f pvc-sc.yaml 
persistentvolumeclaim/pvc-sc created

[root@k8s-m1 ~]# kubectl  get pvc
NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-sc   Bound    pvc-63eee4c7-90fd-4c7e-abf9-d803c3204623   1Mi        RWX            nfs-storage    3s
pvc1     Bound    pv1                                        1Gi        RWO            nfs            24m

[root@k8s-m1 ~]# kubectl  get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
pv1                                        1Gi        RWO            Recycle          Bound    default/pvc1     nfs                     49m
pvc-63eee4c7-90fd-4c7e-abf9-d803c3204623   1Mi        RWX            Retain           Bound    default/pvc-sc   nfs-storage              7s

我们修改下nginx的yaml配置,将pvc的名称换成上面的pvc-sc:

[root@k8s-m1 ~]# vim nginx.yaml 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.21.6
        name: nginx
        volumeMounts:    # 我们这里将nginx容器默认的页面目录挂载
          - name: html-files
            mountPath: "/usr/share/nginx/html"
      volumes:
        - name: html-files
          persistentVolumeClaim:
            claimName: pvc-sc
            
            
[root@k8s-m1 ~]# kubectl apply -f nginx.yaml 
service/nginx unchanged
deployment.apps/nginx configured

# 这里注意下,因为是动态生成的pv,所以它的目录基于是一串随机字符串生成的,这时我们直接进到pod内来创建访问页面
[root@k8s-m1 ~]# kubectl exec -it nginx-57cdc6d9b4-n497g -- bash
root@nginx-57cdc6d9b4-n497g:/# echo 'storageClass used' > /usr/share/nginx/html/index.html
root@nginx-57cdc6d9b4-n497g:/# exit

# curl 10.68.238.54                              
storageClass used

# 我们看下NFS挂载的目录
# ll /nfs_dir/
total 0
drwxrwxrwx 2 root root 24 Nov 27 17:52 default-pvc-sc-pvc-63eee4c7-90fd-4c7e-abf9-d803c3204623
drwxr-xr-x 2 root root  6 Nov 27 17:25 pv1
posted @ 2024-08-05 20:50  &UnstopPable  阅读(169)  评论(0编辑  收藏  举报