本篇文章主要介绍卷的用途、卷的类型,以及卷是如何工作的。

1. 卷的用途

容器中的文件在磁盘上是临时存放的,当容器崩溃或被停止时,容器的状态不会被保存,因此在容器生命期内创建或修改的所有文件都将丢失。 在崩溃之后,kubelet 会以干净的状态重启容器。

卷为Pod中的容器提供了数据持久和共享存储的方式。

  • 在同一个 Pod 中的两个不同容器之间共享文件系统
  • 在两个不同的 Pod 之间共享文件系统(即使这些 Pod 运行在不同的节点上)
  • 数据共享可以发生在容器内不同本地进程之间,或在不同容器之间,或在多个 Pod 之间。
  • 持久化存储数据,这样即使 Pod 重启或被替换,存储的数据仍然可用

  • K8s 中,卷基于ConnfigMap 或 Secret 为Pod填充配置文件
  • 基于容器所在 Pod 的详细信息,将配置信息传递给运行在容器中的应用 

  • 以只读权限访问另一个容器镜像中的数据

2. 卷的类型

临时卷:是一种生命周期与 Pod 紧密绑定的存储卷。当 Pod 被删除时,Kubernetes 会自动销毁并清理这个临时卷及其上的所有数据。

它与持久卷(Persistent Volume, PV)形成鲜明对比,持久卷的生命周期是独立的,Pod 被删除后,持久卷及其数据依然存在,可以被其他 Pod 重新挂载使用。

Kubernetes 中的临时卷主要包含以下几类:

  1. emptyDir:最基础、最常用的临时卷类型。

  2. configMapsecretdownwardAPI:这些特殊的卷类型,其数据由 Kubernetes API 本身提供(分别是 ConfigMap 资源、Secret 资源和 Pod 的元数据),它们也是临时的,因为卷本身(挂载点)随 Pod 的创建而创建,随 Pod 的删除而消失。但需要注意的是,它们的数据来源(如 ConfigMap)的生命周期可能是独立的。

  3. CSI 临时卷:这是一个更强大的功能,允许支持特定 CSI 驱动程序的第三方存储提供商也提供临时卷。这为临时存储带来了持久化存储才有的高级功能(如快照、扩容等)。

3. 卷的用法

3.1临时卷的用途及示例:

1. 容器间数据共享

这是 emptyDir 最经典的用途。一个 Pod 中可能运行多个协作的容器(Sidecar 模式),它们需要共享一些数据。

示例--Web 服务器与日志收集器:

一个容器(如 Nginx)将访问日志写入 emptyDir 卷中的某个文件,另一个容器(如 Filebeat 或 Fluentd 的 Sidecar)从同一个卷中读取日志文件并将其发送到中央日志系统(如 Elasticsearch)。

apiVersion: v1
kind: Pod
metadata:
  name: shared-volume-pod
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    volumeMounts:
    - name: shared-data
      mountPath: /var/log/nginx # Nginx将日志写入这里
  - name: log-collector
    image: fluent/fluentd:latest
    volumeMounts:
    - name: shared-data
      mountPath: /fluentd/log # Fluentd从这里读取日志
  volumes:
  - name: shared-data
    emptyDir: {} # 关键:定义一个emptyDir临时卷

2. 作为缓存或临时工作区

应用程序可能需要一个磁盘空间来存放临时计算数据、缓存文件或中间结果。使用临时卷非常合适,因为当 Pod 完成工作或被驱逐时,这些数据就不再需要,会自动清理。

示例:

  • 大型软件编译:在一个 CI/CD 流水线的 Pod 中,编译容器可以将依赖库(如 node_modules 或 .m2 仓库)缓存到 emptyDir 中,以加速后续的编译步骤(在同一 Pod 内)。

  • 数据批处理:一个数据处理任务可以将中间结果暂存到 emptyDir,任务完成后数据即可丢弃。

3. 检查点或恢复

有些应用程序在运行过程中需要定期将状态保存到磁盘,以便在崩溃时能够快速恢复。由于 Pod 可能被重新调度到另一个节点,这种状态通常不适合用 emptyDir 来持久化。但在某些单次运行或可容忍从头开始的场景下,可以使用它来暂存状态,以应对容器内进程的重启(而非整个 Pod 的重启)。

3.2 持久卷的用途及示例

Kubernetes 的持久卷类别非常丰富,以下是按照技术实现分类的持久卷类别,并以表格形式总结。

在Kubernetes中,持久卷(PersistentVolume, PV)和持久卷声明(PersistentVolumeClaim, PVC)是用于管理存储资源的重要资源。它们使得Pod可以持久化存储数据,这对于状态持久化应用(如数据库)非常关键。

1. 创建持久卷(PersistentVolume, PV)
首先,你需要创建一个或多个持久卷,这些卷代表了底层的存储资源,如NFS、GlusterFS、Ceph、AWS EBS等。

示例:创建一个NFS类型的PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs-storage
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /path/to/nfs/export
    server: nfs-server.example.com

2. 创建持久卷声明(PersistentVolumeClaim, PVC)

然后,你可以创建一个或多个持久卷声明,这些声明代表了用户对存储资源的需求。PVC会绑定到一个PV上。

示例:创建一个PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs-storage
  resources:
    requests:
      storage: 1Gi

3. 在Pod中使用PVC
最后,你可以在Pod的配置中引用这个PVC,以使用持久存储。

示例:在Pod中使用PVC

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

4. 验证和测试
部署Pod后,你可以检查Pod的状态,并验证是否正确挂载了PVC。使用kubectl命令:

kubectl get pod my-pod
kubectl exec -it my-pod -- df -hT | grep /var/www/html

3.3 HostPath 和Local

在Kubernetes中,Local和HostPath都是用于本地存储的持久卷类型,但它们在设计目标和使用场景上有重要区别。

HostPath适用场景:

  • 开发和测试环境

  • 需要访问节点系统文件的场景(如日志收集)

  • 单节点集群或不需要数据持久性的场景

Local Volume适用场景:

  • 生产环境本地存储

  • 需要数据持久性和卷生命期管理

  • 使用本地SSD等高性能存储的场景

HostPath将节点上的文件系统目录挂载到Pod中,主要用于开发测试或需要访问节点特定文件的场景。

Local Volume是Kubernetes 1.14后稳定的功能,专为本地存储设计,支持动态 provisioning,更适合生产环境。

HostPath示例:

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
  - name: test-container
    image: nginx
    volumeMounts:
    - name: hostpath-volume
      mountPath: /host-data
  volumes:
  - name: hostpath-volume
    hostPath:
      path: /data/hostpath
      type: DirectoryOrCreate  # 目录不存在时自动创建

local 卷只能用作静态创建的持久卷。不支持动态配置。

与 hostPath 卷相比,local 卷能够以持久和可移植的方式使用,而无需手动将 Pod 调度到节点。系统通过查看 PersistentVolume 的节点亲和性配置,就能了解卷的节点约束。

然而,local 卷仍然取决于底层节点的可用性,并不适合所有应用程序。 如果节点变得不健康,那么 local 卷也将变得不可被 Pod 访问。使用它的 Pod 将不能运行。 使用 local 卷的应用程序必须能够容忍这种可用性的降低,以及因底层磁盘的耐用性特征而带来的潜在的数据丢失风险。

下面是一个使用 local 卷和 nodeAffinity 的持久卷示例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - example-node

使用 local 卷时,你需要设置 PersistentVolume 对象的 nodeAffinity 字段。 Kubernetes 调度器使用 PersistentVolume 的 nodeAffinity 信息来将使用 local 卷的 Pod 调度到正确的节点。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐