Kubernetes-subpath的使用

lightinglei發表於2020-06-14

一、什麼是subpath

為了支援單一個pod多次使用同一個volume而設計,subpath翻譯過來是子路徑的意思,如果是資料卷掛載在容器,指的是儲存卷目錄的子路徑,如果是配置項configMap/Secret,則指的是掛載在容器的子路徑。

 

二、subpath的使用場景

1、 1個pod中可以拉起多個容器,有時候希望將不同容器的路徑掛載在儲存卷volume的子路徑,這個時候需要用到subpath

2、volume支援將configMap/Secret掛載在容器的路徑,但是會覆蓋掉容器路徑下原有的檔案,如何支援選定configMap/Secret的每個key-value掛載在容器中,且不會覆蓋掉原目錄下的檔案,這個時候也可以用到subpath

 

三、subpath的使用

1、儲存卷

    採用hostpath的方式建立PV,宿主機的對映目錄為/data/pod/volume5

[root@k8s-master zhanglei]# cat pv-subpath.yaml 
kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-subpath-05
  labels:
    release: stable
spec:
  capacity:
    storage: 0.1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  hostPath:
    path: /data/pod/volume5                 # 宿主機的目錄

[root@k8s-master zhanglei]# kubectl create -f pv-subpath.yaml  

PV建立成功後,再建立PVC

[root@k8s-master zhanglei]# cat pvc-subpath.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-subpath
  namespace: default
spec:
 accessModes: ["ReadWriteOnce"]
 resources:
   requests: 
     storage: 0.05Gi
[root@k8s-master zhanglei]# kubectl create -f pvc-subpath.yaml

在pod中宣告並使用subpath

[root@k8s-master zhanglei]# cat pod-subpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-subpath-zltest
spec:
    containers:
    - name: ubuntu-subpath-container
      image: ubuntu
      volumeMounts:
      - mountPath: /var/lib/ubuntu            # 容器1的掛載目錄
        name: subpath-vol
        subPath: ubuntutest                   # 宿主機volume5的子目錄1
    - name: nginx-subpath-container
      image: nginx
      volumeMounts:
      - mountPath: /var/www/nginx             # 容器2的掛載目錄
        name: subpath-vol
        subPath: nginxtest                   # 宿主機volume5的子目錄2 
    volumes:
    - name: subpath-vol
      persistentVolumeClaim:
        claimName: pvc-subpath               # PVC的名字

  [root@k8s-master zhanglei]# kubectl create -f pod-subpath.yaml

[root@k8s-master zhanglei]# kubectl describe pod  pod-subpath-zltest 
Name:         pod-subpath-zltest
Namespace:    default
Priority:     0
Node:         k8s-master/192.168.126.129
Start Time:   Fri, 29 May 2020 16:45:49 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 10.122.235.235/32
              cni.projectcalico.org/podIPs: 10.122.235.235/32
Status:       Running
IP:           10.122.235.235
IPs:
  IP:  10.122.235.235
Containers:
  ubuntu-subpath-container:
    Container ID:   docker://6e5cb30ee7e03b77d2ca22e4cd818ff326fa40836427fe17b1584646b4388dce
    Image:          ubuntu
    Image ID:       docker-pullable://ubuntu@sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Sun, 14 Jun 2020 22:38:11 +0800
      Finished:     Sun, 14 Jun 2020 22:38:11 +0800
    Ready:          False
    Restart Count:  558
    Environment:    <none>
    Mounts:
      /var/lib/ubuntu from subpath-vol (rw,path="ubuntutest")
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
  nginx-subpath-container:
    Container ID:   docker://95101741eb1b6aa4c1e53d8fc4ab8006e74fd2eb923eca211ca20a01edcd7630
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Fri, 29 May 2020 16:47:14 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
      /var/www/nginx from subpath-vol (rw,path="nginxtest")
Conditions:
  Type              Status
  Initialized       True 
  Ready             False 
  ContainersReady   False 
  PodScheduled      True 
Volumes:
  subpath-vol:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  pvc-subpath
    ReadOnly:   false
  default-token-74s86:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-74s86
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason   Age                    From                 Message
  ----     ------   ----                   ----                 -------
  Normal   Pulled   21m (x555 over 16d)    kubelet, k8s-master  Successfully pulled image "ubuntu"
  Normal   Created  21m (x555 over 16d)    kubelet, k8s-master  Created container ubuntu-subpath-container
  Normal   Started  21m (x555 over 16d)    kubelet, k8s-master  Started container ubuntu-subpath-container
  Normal   Pulling  6m10s (x562 over 16d)  kubelet, k8s-master  Pulling image "ubuntu"
  Warning  BackOff  71s (x11744 over 16d)  kubelet, k8s-master  Back-off restarting failed container

現在來驗證下在宿主機儲存卷的目錄下是否有2個子目錄,1個是ubuntutest用來掛載容器1的,另外1個是nginxtest用來掛載容器2的

[root@k8s-master /]# cd data/pod/volume5
[root@k8s-master volume5]# ls
nginxtest ubuntutest
[root@k8s-master volume5]# cd nginxtest/     # 可以看到是1個目錄,非檔案
[root@k8s-master nginxtest]#

進入到容器中,掛載一個檔案,驗證是否可以同步到儲存卷

[root@k8s-master nginxtest]# kubectl exec -it pod-subpath-zltest -c nginx-subpath-container -- bash
root@pod-subpath-zltest:/# cd /var/www/nginx
root@pod-subpath-zltest:/var/www/nginx# ls
nginx-test-subpath.txt
[root@k8s-master volume5]# cd nginxtest/
[root@k8s-master nginxtest]# ls
nginx-test-subpath.txt

可以看到容器1的目錄/var/www/nginx 和儲存卷的子目錄 nginxtest完成了對映,容器2類似,這裡不再贅述。

2、配置項-configMap

1)建立configMap

[root@k8s-master consecret]# cat conf-subpath.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: conf-subpath-zltest
  namespace: default
data:
  example.property.1: hello      # key-value鍵值對
  example.property.2: world
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3

2)在Pod中使用configMap

[root@k8s-master consecret]# cat pod-conf-subpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    purpose: test-configmap-volume
  name: pod-conf-testvolume
spec:
  containers:
    - name: test-configmap-volume
      image: nginx
      volumeMounts:
        - name: config-volume
          mountPath: /etc/nginx/example.property.1       # 容器掛載目錄
          subPath: example.property.1                    # 將key名稱作為檔名,hello作為檔案內容
  volumes:
    - name: config-volume
      configMap:
         name: conf-subpath-zltest      # 指定使用哪個CM
        
[root@k8s-master consecret]# kubectl create -f pod-conf-subpath.yaml 
[root@k8s-master consecret]# kubectl describe pod  pod-conf-testvolume 
Name:         pod-conf-testvolume
Namespace:    default
Priority:     0
Node:         k8s-master/192.168.126.129
Start Time:   Wed, 03 Jun 2020 11:46:36 +0800
Labels:       purpose=test-configmap-volume
Annotations:  cni.projectcalico.org/podIP: 10.122.235.249/32
              cni.projectcalico.org/podIPs: 10.122.235.249/32
Status:       Running
IP:           10.122.235.249
IPs:
  IP:  10.122.235.249
Containers:
  test-configmap-volume:
    Container ID:   docker://e2cf37cb24af32023eb5d22389545c3468104a4344c47363b5330addc40cb914
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:883874c218a6c71640579ae54e6952398757ec65702f4c8ba7675655156fcca6
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 03 Jun 2020 11:46:53 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /etc/nginx/example.property.1 from config-volume (rw,path="example.property.1")  
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  config-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      conf-subpath-zltest
    Optional:  false
  default-token-74s86:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-74s86
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:          <none>

在容器掛載路徑驗證下是否將configMap中example.property.1掛載在容器中,且是否會覆蓋掉原有的目錄

root@pod-conf-testvolume:/# cd  /etc/nginx 
root@pod-conf-testvolume:/etc/nginx# ls
conf.d            fastcgi_params  koi-win    modules     scgi_params   win-utf
example.property.1  koi-utf        mime.types    nginx.conf  uwsgi_params

從上可以看到example.property.1已經掛載到容器中,且未對目錄原有的檔案進行覆蓋

root@pod-conf-testvolume:/etc/nginx# cd example.property.1 
bash: cd: example.property.1: Not a directory
root@pod-conf-testvolume:/etc/nginx# cat example.property.1 
helloroot@pod-conf-testvolume:/etc/nginx# 

從上可以驗證configMap的subpath用法支援將configMap中的每對key-value以key名稱作為檔名,value作為檔案內容掛載到容器的目錄中。

四、總結

本文介紹了subpath分別在持久化儲存卷和配置項configMap中的使用,豐富了volume在pod中的使用場景。