讲解

容器的文件系统是临时的:容器重启(同一 Pod 内)文件还在,但 Pod 删除重建就全没了;而且同一 Pod 里多个容器之间想共享文件也没门路。Volume(存储卷)解决这两个问题:它是 Pod 级别声明、容器里挂载使用的目录,生命周期跟着 Pod 走。Kubernetes 支持几十种卷类型,但学习阶段掌握三个就够用:emptyDir、hostPath、以及下一章的 PersistentVolumeClaim。

emptyDir 是「Pod 级临时目录」:Pod 创建时在节点上开一个空目录,Pod 删除时随之一同删除;容器崩溃重启不影响它(所以它能扛住容器重启,扛不住 Pod 删除)。经典用途是同 Pod 多容器共享文件——比如一个容器产出静态页面,另一个容器(nginx)对外服务。hostPath 是把节点宿主机上的目录挂进 Pod,数据跟着节点走,Pod 调度到别的节点就看不到了——它主要给系统组件用(比如节点日志采集器读 /var/log),业务应用用它等于把自己钉死在节点上,要非常谨慎。

卷的声明分两层,这是初学者最容易绕晕的地方:spec.volumes 里「声明」卷(名字 + 类型 + 来源),每个容器的 volumeMounts 里「挂载」卷(卷名 + 容器内路径)。同一声明可以被多个容器挂到不同路径。挂载点还有个细节:容器内路径下原有内容会被卷遮住(不是删除,是看不见),所以把卷挂到镜像里有数据的目录前要想清楚。

示例

emptyDir 共享实战:writer 容器每 5 秒把时间写进共享目录,web 容器(nginx)把同一目录对外服务:

# wait: pod/ohmydocs-verify-share
apiVersion: v1
kind: Pod
metadata:
  name: ohmydocs-verify-share
  labels:
    app: ohmydocs-verify-share
spec:
  containers:
    - name: writer
      image: busybox:1.36
      command:
        - sh
        - -c
        - |
          echo '<h1>emptyDir 共享卷</h1>' > /data/index.html
          while true; do date >> /data/heartbeat.log; sleep 5; done
      volumeMounts:
        - name: shared
          mountPath: /data
    - name: web
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80
      volumeMounts:
        - name: shared
          mountPath: /usr/share/nginx/html
  volumes:
    - name: shared
      emptyDir: {}

两个容器看到的是同一个目录:web 容器能服务 writer 写的页面,heartbeat 在持续增长:

kubectl exec ohmydocs-verify-share -c web -- wget -qO- http://127.0.0.1/
kubectl exec ohmydocs-verify-share -c writer -- tail -2 /data/heartbeat.log

hostPath 的样子(把节点目录挂进容器;它把 Pod 绑死在节点文件系统上,此处只做客户端校验,不真的挂节点目录):

# 仅示意:hostPath 依赖节点本地目录,可移植性差且有安全风险,仅演示字段结构
apiVersion: v1
kind: Pod
metadata:
  name: ohmydocs-verify-hostpath
spec:
  containers:
    - name: busybox
      image: busybox:1.36
      command: ["sleep", "3600"]
      volumeMounts:
        - name: node-logs
          mountPath: /node-logs
          readOnly: true
  volumes:
    - name: node-logs
      hostPath:
        path: /var/log
        type: Directory

常见坑

  • 指望 emptyDir 持久化:Pod 一删 emptyDir 就没——它只是「容器重启安全」的临时空间,要持久化用下一章的 PVC。
  • volumeMounts 名字对不上 volumes:挂载引用了不存在的卷名,Pod 直接创建失败;声明与挂载的名字必须一致。
  • 挂载遮住镜像内容:把卷挂到 /usr/share/nginx/html 这类镜像自带内容的目录,原内容被遮住——用 emptyDir 时首页变 403/404 多半是这里。
  • 业务用 hostPath:数据跟着节点漂移、多副本互相看不见对方数据,还有提权风险;除非写节点级 agent,别碰。

小结

Volume 是 Pod 级目录:emptyDir 临时共享、hostPath 绑节点(慎用)、声明与挂载分两层。真正的持久化要让存储的生命周期独立于 Pod——下一章 PersistentVolume 与 PersistentVolumeClaim。