• 【云原生】k8s中volumeMounts.subPath的巧妙用法


    一、概述

    有时,在单个 Pod 中共享卷以供多方使用是很有用的。volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。

    官方文档:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/#using-subpath

    二、使用场景

    1. 一个共享卷, 挂载多个路径。
    2. ConfigMap或Secret挂载到特定目录的特定路径, 而 该目录下已经有其他文件且不希望被覆盖掉。

    三、共享卷中使用, 挂载多个路径

    作为configmap/secret使用时,subPath代表configmap/secret的子路径。

    【示例1】挂载目录,hostPath

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-lamp-site
    spec:
        nodeName: local-168-182-110 # 为了测试方便,指定调度机器
        containers:
        - name: mysql
          image: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: "rootpasswd"
          volumeMounts:
          - mountPath: /var/lib/mysql #挂载到容器的某个路径下
            name: site-data #挂载设备的名字,与volumes[*].name 需要对应 
            subPath: mysql # volumes path中的子路径(会自动在volumes path目录下创建mysql空目录)
        - name: php
          image: php:7.0-apache
          volumeMounts:
          - mountPath: /var/www/html #挂载到容器的某个路径下
            name: site-data # volumes path中的子路径(会自动在volumes path目录下创建site-data【空目录】)
            subPath: html
        volumes:
          - name: nginx #和上面保持一致 这是本地的文件路径,上面是容器内部的路径
            hostPath:
              path: /opt/k8s/subPath/lamp #此路径需要实现创建
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    【示例2】挂载目录,pvc

    # StorageClass
    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: local-storage
    provisioner: kubernetes.io/no-provisioner
    volumeBindingMode: WaitForFirstConsumer
    ---
    # pvc 
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: local-lamp-pv
      labels:
        name: local-lamp-pv
    spec:
      capacity:
        storage: 1Gi
      accessModes:
      - ReadWriteOnce
      persistentVolumeReclaimPolicy: Retain
      storageClassName: local-storage
      local:
        path: /opt/k8s/subPath/lamp-pvc
      nodeAffinity:
        required:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - local-168-182-110
    
    ---
    # pvc 
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: my-lamp-site-data
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi 
      storageClassName: local-storage
      selector:
        matchLabels:
          name: local-lamp-pv
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: my-lamp-site-pvc
    spec:
        containers:
        - name: mysql
          image: mysql
          env:
          - name: MYSQL_ROOT_PASSWORD
            value: "rootpasswd"
          volumeMounts:
          - mountPath: /var/lib/mysql
            name: site-data
            subPath: mysql
        - name: php
          image: php:7.0-apache
          volumeMounts:
          - mountPath: /var/www/html
            name: site-data
            subPath: html
        volumes:
        - name: site-data
          persistentVolumeClaim:
            claimName: my-lamp-site-data
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    如果使用PVC模板就不用手动创建PVC了,示例如下:

      volumeClaimTemplates:   #可看作pvc的模板
      - metadata:
          name: nginx-pvc
        spec:
          accessModes: [ "ReadWriteOnce" ]
          storageClassName: "local-storage"  #存储类名,就是上面nginx-sc.yaml metadata.name
          resources:
            requests:
              storage: 1Gi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    【示例3】共享单个文件
    那么如果 subPath 不是文件夹,而是一个文件,又该如何解决呢?同样的道理,只需要通过 subPath 指定出该文件即可,注意 subPath 要使用相对目录。具体如下所示:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-test
    spec:
      replicas: 1
      selector:
        matchLabels:
         app: nginx-pod
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          nodeName: local-168-182-110 # 为了测试方便,指定调度机器
          containers:
          - name: nginx
            image: docker.io/library/nginx:latest
            volumeMounts:
            - mountPath: /etc/nginx/nginx.conf
              name: nginx-conf
              subPath: nginx-conf
          volumes:
          - name: nginx-conf #和上面保持一致 这是本地的文件路径,上面是容器内部的路径
            hostPath:
              path: /opt/k8s/subPath/nginx #此路径需要实现创建
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    【结论】以宿主机上的文件为准,会覆盖pod里原先默认的的文件内容。

    四、ConfigMap 和 Secret 中使用 subPath

    作为configmap/secret使用时,subPath代表configmap/secret的子路径。如果不使用subPath会把容器里原本的文件(volumeMounts.mountPath对应的目录)都清空,自会把ConfigMap 和 Secret 的文件放在volumeMounts.mountPath对应的目录下。

    【示例1】ConfigMap

    apiVersion: v1
    kind: ConfigMap
    metadata: 
      name: nginx-conf
    data:
      nginx.conf: |+
        worker_processes  1;
        events {
            worker_connections  1024;
        }
        http {
            include       mime.types;
            default_type  application/octet-stream;
            sendfile        on;
            keepalive_timeout  65;
    
            server {
                listen       80;
                server_name  localhost;
                location / {
                    root   html;
                    index  index.html index.htm;
                }
                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                    root   html;
                }
            }
        }
    ---
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-test2
    spec:
      replicas: 1
      selector:
        matchLabels:
         app: nginx-pod
      template:
        metadata:
          labels:
            app: nginx-pod
        spec:
          nodeName: local-168-182-110 # 为了测试方便,指定调度机器
          containers:
          - name: nginx
            image: docker.io/library/nginx:latest
            volumeMounts:
            - name: nginx-cm # 与volumes.name一致
              mountPath: /etc/nginx/nginx.conf
              subPath: nginx.conf
          volumes:
          - name: nginx-cm
            configMap:
              name: nginx-conf # configMap名称
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    【示例1】Secret

    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque
    data:
      username: admin
      password: MWYyZDFlMmU2N2Rm
    
    ---
    
    vim myapp-demo.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mysql-demo
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: myapp
      template:
        metadata:
          labels:
            app: myapp
        spec:
          containers:
          - name: myapp
            image: mysql
            imagePullPolicy: IfNotPresent
            ports:
            - name: http
              containerPort: 80
            volumeMounts:
            - name: mysql
              mountPath: /tmp/data
              subPath: data
          volumes:
          - name: mysql
            secret:
              secretName: mysecret
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    【结论】会在/tmp目录下面存放data文件信息,如果存在则覆盖。如果不存在,则自动创建。


    最后对volumeMounts.subPath来一个总结:

    • subPath其实就是volumes挂载的子目录或单个文件,是不是目录和单文件,取决于subPath在volumes挂载的目录下是否存在subPath定义的文件(文件或目录),如果不存在,则会volumes对应的目录下创建一个subPath目录。
    • 如果ConfigMap 和 Secret 中使用 subPath,如果不指定subPath,则会把volumeMounts.mountPath对应的目录下的文件都清掉,然后只存放ConfigMap 或者 Secret 定义的文件。

    关于volumeMounts.subPath的用法就先到这里了,有疑问的小伙伴,欢迎给我留言哦,后续文章更精彩,请小伙伴耐心等待哦~

  • 相关阅读:
    如何造数据&对拍
    排列组合——n个人平均分成m组
    thinkphp5.0.24反序列化链子分析
    液压比例方向阀放大器组装
    网络编程基础
    IDEA创建一个JavaWeb项目详细步骤
    HSQL总结
    关于AbstractQueuedSynchronizer的enq()方法的代码问题
    通过转义字符获取标签内的文字js通过转义字符获取字符串标签内的文字||获取字符串标签内的文字并加校验是否修改
    dragonfly数据库
  • 原文地址:https://blog.csdn.net/qq_35745940/article/details/126594472