You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的默认行为,而是通过容器启动初始化脚本实现数据保留:

  1. 容器启动时,先检查挂载的PVC目录(/var/lib/grafana)是否为空或缺少必要初始化文件(如grafana.db、核心目录结构)。
  2. 若PVC目录为空,脚本会将镜像内置的初始数据从备份目录(如镜像中预先准备的/usr/share/grafana/conf或专用初始化目录)复制到/var/lib/grafana。
  3. 完成初始化后,再启动Grafana主进程。
    这种方式既利用PVC实现持久化存储,又保证首次启动时的初始数据可用,后续启动直接使用PVC中已有的数据,不会重复复制。

自行实现该效果的步骤

要复刻这种行为,需在自定义镜像中添加初始化逻辑:

  1. 调整Dockerfile:将初始数据放在非挂载目录中,避免被PVC覆盖
    FROM busybox:latest
    
    # 创建目标挂载目录和初始数据备份目录
    RUN mkdir -p /var/aaaa /var/aaaa-init
    # 将初始文件复制到备份目录
    COPY ./main.go /var/aaaa-init/
    
  2. 编写初始化脚本(如/init.sh),实现条件复制逻辑
    #!/bin/sh
    
    # 检查挂载目录是否为空
    if [ -z "$(ls -A /var/aaaa)" ]; then
        # 将备份目录的初始数据复制到挂载目录
        cp -r /var/aaaa-init/* /var/aaaa/
    fi
    
    # 执行容器原本的启动命令
    exec sleep 86400
    
  3. 更新Dockerfile:添加脚本并设置为启动命令
    COPY ./init.sh /
    RUN chmod +x /init.sh
    CMD ["/init.sh"]
    
  4. 重新构建镜像并部署后,首次启动时挂载目录为空,脚本自动复制初始数据;后续启动时挂载目录已有数据,不会重复复制,原数据与持久化数据均可正常访问。

内容的提问来源于stack exchange,提问作者HHJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:02:08