什么是 Kubernetes 卷?

Kubernetes 卷是为 Pod 中的容器提供了一种通过文件系统访问和共享数据的方式。它解决了两个核心问题:

  1. 数据持久性问题:容器中的文件是临时的,当容器崩溃或被停止时,所有数据都会丢失。
  2. 数据共享问题:当多个容器在一个 Pod 中运行时,它们之间共享文件系统很困难。

卷本质上是一个目录,Pod 中的容器可以访问该目录中的数据。不同类型的卷决定了该目录如何形成、使用什么介质保存数据以及目录中存放的内容。

为什么需要卷?

想象一下:你运行一个 Web 服务器容器,它需要存储用户上传的图片。如果没有卷,当容器重启时,所有上传的图片都会丢失。卷就解决了这个问题,让你的数据在容器重启后仍然可用。

卷的核心概念

  • 卷的生命期:临时卷(如 emptyDir)与 Pod 绑定,当 Pod 被删除时卷也被删除;持久卷(如 PersistentVolume)可以比 Pod 的生命周期更长。
  • 挂载点:在 Pod 配置中,通过 .spec.volumes 定义卷,通过 .spec.containers[*].volumeMounts 声明卷在容器中的挂载位置。
  • 卷类型:Kubernetes 支持多种卷类型,每种类型适用于不同场景。

卷的使用方式

在 Pod 规范中,你需要做两件事:

  1. 在 .spec.volumes 中定义卷
  2. 在 .spec.containers[*].volumeMounts 中指定卷挂载位置

示例:

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: example-container
    image: nginx
    volumeMounts:
    - name: my-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: my-volume
    emptyDir: {}

常见卷类型详解

1. ConfigMap 卷

用于将 ConfigMap 中的数据注入到 Pod 中,作为文件或环境变量。

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
  - name: test
    image: busybox:1.28
    command: ['sh', '-c', 'echo "The app is running!" && tail -f /dev/null']
    volumeMounts:
    - name: config-vol
      mountPath: /etc/config
  volumes:
  - name: config-vol
    configMap:
      name: log-config
      items:
      - key: log_level
        path: log_level.conf

2. emptyDir 卷

在 Pod 被分配到节点时创建的临时目录,当 Pod 从节点删除时数据也会被永久删除。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi
      medium: Memory  # 使用内存作为存储介质

3. hostPath 卷

将主机节点文件系统上的文件或目录挂载到 Pod 中,有安全风险,应尽量避免使用。

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-linux
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: example-container
    image: registry.k8s.io/test-webserver
    volumeMounts:
    - mountPath: /foo
      name: example-volume
      readOnly: true
  volumes:
  - name: example-volume
    hostPath:
      path: /data/foo
      type: Directory  # 必须是目录

4. secret 卷

用于传递敏感信息(如密码),数据存储在内存中(tmpfs),不会持久化。

apiVersion: v1
kind: Pod
metadata:
  name: secret-pod
spec:
  containers:
  - name: secret-container
    image: nginx
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: my-secret

5. persistentVolumeClaim 卷

用于将持久卷(PersistentVolume)挂载到 Pod 中,是用户"申领"持久存储的方式。

apiVersion: v1
kind: Pod
metadata:
  name: pvc-pod
spec:
  containers:
  - name: pvc-container
    image: nginx
    volumeMounts:
    - name: pvc-volume
      mountPath: /var/lib/mysql
  volumes:
  - name: pvc-volume
    persistentVolumeClaim:
      claimName: my-pvc

6. NFS 卷

将 NFS(网络文件系统)挂载到 Pod 中。

apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
spec:
  containers:
  - name: nfs-container
    image: nginx
    volumeMounts:
    - name: nfs-volume
      mountPath: /my-nfs-data
  volumes:
  - name: nfs-volume
    nfs:
      server: my-nfs-server.example.com
      path: /my-nfs-volume
      readOnly: true

7. CSI 卷(推荐使用)

Kubernetes 推荐的卷类型,通过 CSI(容器存储接口)驱动实现,支持各种云存储和第三方存储。

apiVersion: v1
kind: Pod
metadata:
  name: csi-pod
spec:
  containers:
  - name: csi-container
    image: nginx
    volumeMounts:
    - name: csi-volume
      mountPath: /csi-data
  volumes:
  - name: csi-volume
    csi:
      driver: example.com/csi-driver
      volumeHandle: "volume-12345"
      readOnly: false
      volumeAttributes:
        type: ssd
        size: 10Gi

卷类型更新与弃用

Kubernetes 1.33 版本中,许多树内(In-Tree)卷类型已被弃用,推荐使用 CSI 驱动:

  • awsElasticBlockStore → ebs.csi.aws.com
  • azureDisk → disk.csi.azure.com
  • azureFile → file.csi.azure.com
  • gcePersistentDisk → pd.csi.storage.gke.io
  • vsphereVolume → csi.vsphere.vmware.com
  • portworxVolume → pxd.portworx.com
  • cephfsglusterfsrbd 已被移除

使用 subPath 分享同一卷

可以使用 subPath 在同一卷中为不同容器提供不同的子目录。

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
  containers:
  - name: mysql
    image: mysql
    volumeMounts:
    - mountPath: /var/lib/mysql
      name: site-data
      subPath: mysql
  - name: php
    image: php:7.0-apache
    volumeMounts:
    - mountPath: /var/www/html
      name: site-data
      subPath: html
  volumes:
  - name: site-data
    persistentVolumeClaim:
      claimName: my-lamp-site-data

挂载传播(Mount Propagation)

允许将容器挂载的卷共享到同一 Pod 中的其他容器,甚至共享到同一节点上的其他 Pod。

volumeMounts:
- name: shared-data
  mountPath: /shared
  mountPropagation: Bidirectional

挂载传播类型:

  • None(默认):不感知挂载变化
  • HostToContainer:感知主机挂载变化
  • Bidirectional:双向传播(危险,需特权容器

只读挂载与递归只读挂载

通过 readOnly: true 可以使挂载为只读。

volumeMounts:
- name: config-vol
  mountPath: /etc/config
  readOnly: true

Kubernetes 1.33 引入了递归只读挂载,确保挂载的子目录也变为只读:

volumeMounts:
- name: mnt
  mountPath: /mnt-rro
  readOnly: true
  mountPropagation: None
  recursiveReadOnly: Enabled

树外(Out-of-Tree)卷插件

Kubernetes 1.33 之后,推荐使用 CSI 和 FlexVolume(已弃用)作为树外卷插件:

  • CSI(容器存储接口):标准接口,推荐使用
  • FlexVolume:已弃用,推荐迁移到 CSI

卷选择指南

场景 推荐卷类型 说明
临时缓存 emptyDir 临时存储,节点重启后丢失
配置文件 ConfigMap 注入配置数据
敏感信息 secret 传递密码等敏感信息
共享文件系统 NFS 跨 Pod 共享数据
云存储 CSI 驱动 AWS EBS、Azure Disk 等
本地存储 local 本地磁盘,节点亲和性
静态文件 hostPath 有安全风险,不推荐
代码仓库 gitRepo 已弃用,不推荐

为什么卷很重要?

  1. 数据持久性:确保数据在 Pod 重启后仍然存在
  2. 数据共享:让 Pod 中的多个容器共享数据
  3. 灵活性:支持多种存储后端(云存储、本地存储、网络存储等)
  4. 可移植性:通过 PersistentVolume 和 PersistentVolumeClaim,实现存储抽象

总结

Kubernetes 卷是管理容器数据的关键机制。随着 Kubernetes 发展,许多树内卷类型已被弃用,推荐使用 CSI 驱动。理解不同卷类型的特点和适用场景,能帮助你为应用选择合适的存储方案,确保数据持久性和应用可靠性。

在选择卷类型时,优先考虑:

  1. 数据持久性需求
  2. 容器间数据共享需求
  3. 安全性考虑
  4. 云平台兼容性

通过正确使用卷,你可以构建出更可靠、更灵活的 Kubernetes 应用。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐