Kubernetes

k8s数据卷 Volume 之 hostPath 与 emptyDir

转载:k8s数据卷 Volume 之 hostPath 与 emptyDir

 

一、为什么需要 volume(数据卷)?


容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题。

  • 问题1:当容器升级或者崩溃时,kubelet会重建容器,容器内文件会丢失
  • 问题2:一个Pod中运行多个容器需要共享文件。

Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。

 

二、常用数据卷


  • 本地(emptyDir,hostPath)
  • 网络(NFS,Ceph,GlusterFS)
  • 公有云(AWS EBS)
  • K8S资源(configmap,secret)

 

三、empryDir


emptyDir卷: 是一个自动创建的、 Pod 所在node主机上的临时目录(node上预设定好的存储位置),与Pod生命周期绑定在一起,如果Pod删除了,emptyDir卷也会被删除。
应用场景: Pod中容器之间数据共享,常用于同一个pod内容器(container)之间直接的数据传输。

例子

# 做一个测试yaml
vi emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: write # 业务容器(写数据)
    image: centos
    command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
    volumeMounts:
      - name: data
        mountPath: /data
  - name: read # 辅助容器(读数据)
    image: centos
    command: ["bash","-c","tail -f /data/hello"]
    volumeMounts:
      - name: data
        mountPath: /data
  volumes:
  - name: data
    emptyDir: {}
kubectl apply -f emptydir.yaml

这个 YAML 文件定义了一个 Kubernetes Pod,通过emptyDir 卷实现两个容器间的数据共享。

这是一个典型的主容器 + 辅助容器模式:

  • 主容器(write):循环写入数据到共享目录。
  • 辅助容器(read):实时读取并输出共享目录中的数据。
  • emptyDir 卷:作为临时存储,连接两个容器的数据通路。

 

主容器(写入数据)

- name: write
  image: centos
  command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
  volumeMounts:
    - name: data
      mountPath: /data
  • 每秒向/data/hello文件追加一个数字(从 1 到 100)。
  • >>:追加写入,避免覆盖原有内容。
  • /data目录映射到 emptyDir 卷(data),确保数据可被另一个容器访问。

 

辅助容器(读取数据)

- name: read
  image: centos
  command: ["bash","-c","tail -f /data/hello"]
  volumeMounts:
    - name: data
      mountPath: /data
  • 使用tail -f实时监控并输出/data/hello文件的更新内容。
  • tail -f:持续跟踪文件变化,新内容会立即显示。
  • 与主容器挂载同一 emptyDir 卷,确保能读取到写入的数据。

 

emptyDir 卷(数据共享核心)

volumes:
  - name: data
    emptyDir: {}
  • 在 Pod 内创建一个临时目录,供所有容器共享。
  • 生命周期与 Pod 绑定:Pod 创建时生成,删除时销毁。
  • 容器间可见:所有挂载该卷的容器可读写同一目录。
  • 默认存储在节点磁盘:也可配置为内存存储(medium: Memory)。

 

工作流程

  1. Pod 启动:Kubernetes 创建 Pod,同时初始化 emptyDir 卷(初始为空)。
  2. 数据写入:
    • write容器启动,执行循环脚本。
    • 每秒向/data/hello写入一个数字(如123…)。
  3. 数据读取:
    • read容器启动,执行tail -f /data/hello
    • 实时监控文件变化,新写入的数字会立即显示在read容器的日志中。
  4. 结果验证:
kubectl logs pod1 read  # 查看read容器的日志,会看到递增的数字

执行后,可以看到两个文件data是共享的,测试可以看到两个文件是共享的。

empryDir在k8s中的存储位置

一般在 /var/lib/kubelet/pods/{pod-id}/volumes/kubernetes.io~empty-dir 下。

 

四、hostPath


hostPath卷: 挂载Node文件系统(Pod所在节点)上文件或者目录到Pod中的容器。
应用场景: Pod中容器需要访问宿主机文件。但不适合做持久化。

示例

vi hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod2
spec:
  containers:
  - name: write # 业务容器(写数据)
    image: centos
    command: ["bash","-c","for i in {1..1000};do echo $i >> /data/hello;sleep 1;done"]
    volumeMounts:
      - name: data
        mountPath: /ttt
  volumes:
  - name: data
    hostPath:
      path: /tmp
      type: Directory # 文件类型:定义node主机上的 /tmp 是文件夹还是文件。

测试,在 pod 的 /ttt 目录下写入一个123文件后,查看此pod所处节点

# 查看 pod 所在的 node 
kubectl get pods -o wide

进入node1节点tmp下查看

 

五、emptyDir 与 hostPath 的区别


相同点

  • emptyDir 和 hostPath 类型都可用于 container 之间数据共享。

区别

  • emptyDir 是 pod 级别的。pod 销毁后, emptyDir 也会销毁。
  • emptyDir 被初始化后里面是空的。所有在同一个 pod 中的 container 都可以通过挂载emptyDir后对其进行读写操作。
  • emptyDir 主要用于同一个 pod 中的 container 之间共享数据。(如:log 日志目录)
  • emptyDir 使用 emptyDir 这种 volume 时,一个pod中一般会有2个以上的 container。
  • hostPath 是 node 级别的,node 是持久化的。一个 node 可以创建 N 个 pod 。

 

emptyDir

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app-image
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  - name: sidecar
    image: busybox
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

 

hostPath

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-app
    image: my-app-image
    volumeMounts:
      - name: test-volume
        mountPath: /test-pd
  volumes:
  - name: test-volume 
    hostPath:
      path: /data      # directory on host
      type: Directory  # optional 

# type:
# Other values for type are 'DirectoryOrCreate', 'File', 'FileOrCreate'.