Kubernetes挂载PV后保留原目录文件的实现方法(Grafana案例)
挂载PVC后容器原目录数据仍可访问的原理与实现
问题背景
将PVC挂载到容器目录时,通常会覆盖原目录内容,导致镜像中该目录下的原有文件无法访问。但使用Grafana官方镜像挂载PVC到/var/lib/grafana后,原目录下的数据依然存在且可正常访问;而自行基于BusyBox构建的镜像挂载PVC到/var/aaaa后,原目录下的main.go文件消失。现需了解Grafana的实现方式,以及如何复刻该效果。
Grafana测试案例
StatefulSet配置
apiVersion: apps/v1 kind: StatefulSet metadata: name: grafana-statefulset spec: serviceName: grafana-service selector: matchLabels: app: grafana replicas: 1 template: metadata: labels: app: grafana spec: containers: - name: grafana image: grafana/grafana:latest volumeMounts: - mountPath: "/var/lib/grafana" name: grafana-var securityContext: runAsUser: 472 fsGroup: 472 volumeClaimTemplates: - metadata: name: grafana-var spec: accessModes: ["ReadWriteMany"] storageClassName: nks-nas-csi resources: requests: storage: 2Gi
Pod内目录查看结果
[dev1-user@master-dev-kube-cluster migration]$ k exec -it grafana-statefulset-0 -- sh /usr/share/grafana $ /usr/share/grafana $ ls -l /var/lib/grafana/ total 912 drwxr-x--- 3 grafana root 4096 Jan 2 08:00 alerting drwx------ 2 grafana root 4096 Jan 2 08:00 csv drwxr-x--- 2 grafana root 4096 Jan 2 08:00 file-collections -rw-r----- 1 grafana root 909312 Jan 3 01:20 grafana.db drwxr-xr-x 2 grafana root 4096 Jan 2 08:00 plugins drwx------ 2 grafana root 4096 Jan 2 08:00 png
BusyBox测试案例
镜像Dockerfile
### First Stage FROM busybox:latest RUN mkdir /var/aaaa COPY ./main.go / RUN mv main.go /var/aaaa
StatefulSet配置
apiVersion: apps/v1 kind: StatefulSet metadata: name: busybox spec: serviceName: busybox selector: matchLabels: app: busybox replicas: 1 template: metadata: labels: app: busybox spec: containers: - name: busybox image: busy/test:busybox imagePullPolicy: "Always" command: - sleep - "86400" volumeMounts: - mountPath: /var/aaaa name: www volumeClaimTemplates: - metadata: name: www spec: accessModes: ["ReadWriteMany"] storageClassName: nks-nas-csi resources: requests: storage: 2Gi
Pod内目录查看结果
[dev1-user@master-dev-kube-cluster migration]$ k exec -it busybox-0 -- sh / # / # / # ls -l /var/aaaa/ total 0 / #
原因分析与实现方法
Grafana的实现逻辑
Grafana没有修改Kubernetes挂载PVC的默认行为,而是通过容器启动初始化脚本实现数据保留:
- 容器启动时,先检查挂载的PVC目录(
/var/lib/grafana)是否为空或缺少必要初始化文件(如grafana.db、核心目录结构)。 - 若PVC目录为空,脚本会将镜像内置的初始数据从备份目录(如镜像中预先准备的
/usr/share/grafana/conf或专用初始化目录)复制到/var/lib/grafana。 - 完成初始化后,再启动Grafana主进程。
这种方式既利用PVC实现持久化存储,又保证首次启动时的初始数据可用,后续启动直接使用PVC中已有的数据,不会重复复制。
自行实现该效果的步骤
要复刻这种行为,需在自定义镜像中添加初始化逻辑:
- 调整Dockerfile:将初始数据放在非挂载目录中,避免被PVC覆盖
FROM busybox:latest # 创建目标挂载目录和初始数据备份目录 RUN mkdir -p /var/aaaa /var/aaaa-init # 将初始文件复制到备份目录 COPY ./main.go /var/aaaa-init/ - 编写初始化脚本(如
/init.sh),实现条件复制逻辑#!/bin/sh # 检查挂载目录是否为空 if [ -z "$(ls -A /var/aaaa)" ]; then # 将备份目录的初始数据复制到挂载目录 cp -r /var/aaaa-init/* /var/aaaa/ fi # 执行容器原本的启动命令 exec sleep 86400 - 更新Dockerfile:添加脚本并设置为启动命令
COPY ./init.sh / RUN chmod +x /init.sh CMD ["/init.sh"] - 重新构建镜像并部署后,首次启动时挂载目录为空,脚本自动复制初始数据;后续启动时挂载目录已有数据,不会重复复制,原数据与持久化数据均可正常访问。
内容的提问来源于stack exchange,提问作者HHJ
相关产品推荐
相关产品推荐

