作者 | 江小南


引言

前两天,公司有个同事跑过来问我一件事:我在制作镜像的时候明明把文件已经放到镜像里面去了,为什么kubernetes部署应用的时候文件没有了?听完这话,我看了看Dockerfile是这么写的(不是原文内容,但是意思一样)。

FROM nginx
MAINTAINER jiangxiaonan<xxc113206@163.com>
ENV MYPATH /usr/local
ADD test.tar /nfs/data/01
WORKDIR $MYPATH
EXPOSE 80
CMD /bin/bash

通过Dockerfile可以看出,它是把本地的test.tar包复制并解压到了容器的/nfs/data/01。确实写的没毛病,本地也有相应的tar包。

[root@k8s-master test]# pwd
/root/test
[root@k8s-master test]# ll
total 28
-rw-r--r-- 1 root root   587 Jul  9 18:06 deployment.yaml
-rw-r--r-- 1 root root   142 Jul  9 17:41 Dockerfile
-rw-r--r-- 1 root root     0 Jul  9 16:25 file1.txt
-rw-r--r-- 1 root root     0 Jul  9 16:25 file2.txt
-rw-r--r-- 1 root root   184 Jul  9 16:54 pvc.yaml
-rw-r--r-- 1 root root   212 Jul  9 16:53 pv.yaml
-rw-r--r-- 1 root root 10240 Jul  9 16:26 test.tar
[root@k8s-master test]#

那问题出在了哪里呢?看了一眼yaml,我说你把挂载去掉吧。他去掉挂载重新测试,文件有了。给他讲解了一番,同事连连拍手叫好。

为什么挂载了存储,文件就没有了,而去掉挂载文件又有了?今天就将关于挂载存储的这个小细节讲解给大家。

环境准备

首先我们需要有kubernetes集群。

[root@k8s-master ~]# kubectl get node
NAME          STATUS   ROLES                  AGE     VERSION
k8s-master    Ready    control-plane,master   3m52s   v1.20.9
k8s-worker1   Ready    <none>                 2m8s    v1.20.9
k8s-worker2   Ready    <none>                 2m3s    v1.20.9
[root@k8s-master ~]#

并且安装了存储,我这里使用NFS文件系统。

[root@k8s-master ~]# exportfs
/nfs/data      <world>
[root@k8s-master ~]#

使用上面的Dockerfile制作好镜像。(有Harbor仓库的话也可以使用,如果没有,需要在每个节点制作镜像,防止拉取镜像失败的情况。)

docker build -f ./Dockerfile -t mynginx:1.0 .

由于我们使用的是PV&PVC,所以这里也进行了创建。

# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01-10m
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  nfs:
    path: /nfs/data/01
    server: 172.31.0.2
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 500Mi
  storageClassName: nfs
[root@k8s-master test]# kubectl get pv,pvc
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
persistentvolume/pv01-10m   1Gi        RWX            Retain           Bound    default/nginx-pvc   nfs                     13s

NAME                              STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/nginx-pvc   Bound    pv01-10m   1Gi        RWX            nfs            7s
[root@k8s-master test]#

测试

  1. 有挂载的情况
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
      - image: mynginx:1.0
        imagePullPolicy: Never
        command: [ "/bin/bash", "-ce", "tail -f /dev/null" ]
        name: mynginx
        volumeMounts:
        - name: test
          mountPath: /nfs/data/01
      volumes:
        - name: test
          persistentVolumeClaim:
            claimName: nginx-pvc

通过yaml可以看出,将容器的/nfs/data/01目录进行了挂载。

[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-86477c464b-x5jkd   1/1     Running   0          4s
nginx-deploy-86477c464b-xzqsx   1/1     Running   0          4s
[root@k8s-master test]#
# 成功部署了2个pod,我们进入到pod中一探究竟。
[root@k8s-master test]# kubectl exec -it nginx-deploy-86477c464b-x5jkd -c mynginx -- /bin/bash
root@nginx-deploy-86477c464b-x5jkd:/usr/local# cd /nfs/data/01
root@nginx-deploy-86477c464b-x5jkd:/nfs/data/01# ls
root@nginx-deploy-86477c464b-x5jkd:/nfs/data/01#

按照Dockerfile的编写,/nfs/data/01下应该会有file1.txt和file2.txt两个文件才对,现在并没有。

why?

  1. 没有挂载的情况。

修改我们的yaml,将挂载去掉。

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
      - image: mynginx:1.0
        imagePullPolicy: Never
        command: [ "/bin/bash", "-ce", "tail -f /dev/null" ]
        name: mynginx
[root@k8s-master test]# kubectl apply -f deployment.yaml 
deployment.apps/nginx-deploy created
[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS        RESTARTS   AGE
nginx-deploy-67cd67ff86-dbdbp   1/1     Running       0          5s
nginx-deploy-67cd67ff86-w4wgx   1/1     Running       0          5s
[root@k8s-master test]#
# 成功部署了2个pod,我们进入到pod中一探究竟。
[root@k8s-master test]# kubectl exec -it nginx-deploy-67cd67ff86-dbdbp -c mynginx -- /bin/bash
root@nginx-deploy-67cd67ff86-dbdbp:/usr/local# cd /nfs/data/01
root@nginx-deploy-67cd67ff86-dbdbp:/nfs/data/01# ls
file1.txt  file2.txt
root@nginx-deploy-67cd67ff86-dbdbp:/nfs/data/01#

确实在没有挂载的情况下有了file1.txt和file2.txt。

探究

为了搞清楚这个问题,我们去NFS文件系统中寻找答案。

[root@k8s-master 01]# pwd
/nfs/data/01
[root@k8s-master 01]# ls
[root@k8s-master 01]#

发现文件系统的/nfs/data/01也是空的。这时我们创建文件nfs.txt。

[root@k8s-master 01]# touch nfs.txt
[root@k8s-master 01]# ls
nfs.txt
[root@k8s-master 01]#

然后使用有挂载的deployment.yaml进行测试。

[root@k8s-master test]# kubectl get pod
NAME                            READY   STATUS        RESTARTS   AGE
nginx-deploy-86477c464b-5mhw4   1/1     Running       0          23s
nginx-deploy-86477c464b-wxc8q   1/1     Running       0          21s
[root@k8s-master test]#
# 成功部署了2个pod,我们进入到pod中一探究竟。
[root@k8s-master test]# kubectl exec -it nginx-deploy-86477c464b-5mhw4 -c mynginx -- /bin/bash
root@nginx-deploy-86477c464b-5mhw4:/usr/local# cd /nfs/data/01
root@nginx-deploy-86477c464b-5mhw4:/nfs/data/01# ls
nfs.txt
root@nginx-deploy-86477c464b-5mhw4:/nfs/data/01#

发现我们在NFS中创建的文件被同步到了pod中。而file1.txt和file2.txt并没有出现。

分析总结

我们知道NFS作为持久化的存储,会和容器内的挂载目录进行同步。NFS本身存在的文件会在pod中显示,镜像本身存在的文件却不能显示。