目录

使用pvc持久卷后,持久卷内数据丢失问题

背景:使用dockerhub官方的mongodb 3.6部署了3副本的workload,但是每次重启pod,都会发现原本该pod写入持久卷的数据丢失,经过排查,找到了问题所在。

问题复现

用户使用如下yaml文件创建了workload

 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
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
  namespace: default
spec:
  podManagementPolicy: OrderedReady
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: mongo
  serviceName: mongo
  template:
    metadata:
      labels:
         k8s-app: mongo
    spec:
      containers:
      - command:
        - mongod
        - --bind_ip
        - 0.0.0.0
        - --replSet
        - config
        - --configsvr
        image: mongo:3.6
        imagePullPolicy: IfNotPresent
        name: mongo
        resources: {}
        securityContext:
          privileged: false
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /data
          name: mongo-pvc
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
  updateStrategy:
    rollingUpdate:
      partition: 0
    type: RollingUpdate
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: mongo-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: cbs
      volumeMode: Filesystem

因根据dockerhub页面所描述,默认存放db数据的路径为/data/db:

/images/pvc-data-lose/1.png


故将数据卷挂载至pod内的/data目录看似并无问题,创建后也正常启动,并写入数据,一切看似都再正常不过。

/images/pvc-data-lose/2.png

但是当pod发生重启后,pod内的数据就会全部丢失。

原因分析

通过findmnt命令查询,发现/data/db/data/configdb并未出现在所挂载pvc对应的/data下,而是被挂载至了/dev/vda1

/images/pvc-data-lose/3.png

这就是问题的关键了,那么是什么原因造成此问题的呢?

通过docker history --no-trunc mongo:3.6查看镜像的构建历史发现,此dockerfile在构建时有使用VOLUME命令,手工挂载了/data/db/data/configdb

/images/pvc-data-lose/4.png

dockerfile构建后的镜像中,VOLUME中的操作并不会被kubernetes忽略,而是会继续挂载,如需要将其覆盖,必须要手工指定pvc的挂载点同名,将其覆盖,类似这样

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
spec:
  template:
    spec:
        volumeMounts:
        - mountPath: /data/db
          name: mongo-pvc
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      creationTimestamp: null
      name: mongo-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 10Gi
      storageClassName: cbs
      volumeMode: Filesystem

调整挂载点为/data/db/data/configdb后,再次测试,数据丢失的问题已经消失。

问题反思

为什么之前通过df -h命令,并没有看到/data/db和/data/configdb呢?而只有/data?

/images/pvc-data-lose/5.png

在这里,我们还发现了一个看似奇怪的挂载点/etc/hosts

/images/pvc-data-lose/6.png

经查询,此为引用了docker中的bind-mount特性,结合了multimount,所以,他的真实情况是这样的:

/images/pvc-data-lose/7.png

每一行有多个数据,其中TARGET和SOURCE是我们这次需要关注的,正是这里的multimount,导致了此前被我们忽略的问题

参考文档

What is the meaning of mounting /dev/sda1 to /etc/hosts in Docker container

Use bind mounts