使用 NFS 配置持久存储

Alauda Container Platform 集群支持使用 NFS 的持久存储。Persistent Volumes (PVs) 和 Persistent Volume Claims (PVCs) 为项目内存储卷的配置和使用提供了抽象层。虽然可以直接在 Pod 定义中嵌入 NFS 配置细节,但这种方式不会将卷创建为独立的、隔离的集群资源,增加了冲突的风险。

前提条件

  • 底层基础设施中必须先存在存储,才能在 Alauda Container Platform 中将其挂载为卷。
  • 配置 NFS 卷只需提供 NFS 服务器列表和导出路径。

操作步骤

创建 PV 的对象定义

cat << EOF | kubectl create -f -
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-example
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  nfs:
    path: /tmp
    server: 10.0.0.3
  persistentVolumeReclaimPolicy: Retain
EOF
  1. 卷的名称。
  2. 存储容量。
  3. 虽然看似与控制对卷的访问有关,但实际上它类似于标签,用于将 PVC 与 PV 匹配。目前,基于 accessModes 不会强制执行访问规则。
  4. 使用的卷类型,此处为 nfs 插件。
  5. NFS 服务器地址。
  6. NFS 导出路径。
  7. PVC 删除后采取的操作(Retain、Delete、Recycle)。

验证 PV 是否创建成功

命令
输出示例
kubectl get pv

创建引用该 PV 的 PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-claim1
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  volumeName: pv-nfs-example
  storageClassName: ""
  1. 访问模式不强制安全控制,而是作为标签匹配 PV 和 PVC。
  2. 此声明请求容量为 1Gi 或更大容量的 PV。
  3. 要使用的 PV 名称。

验证持久卷声明是否创建成功

命令
输出示例
kubectl get pvc

通过分区导出实现磁盘配额

为了强制执行磁盘配额和大小限制,可以利用磁盘分区。将每个分区分配为专用导出点,每个导出对应一个独立的 PersistentVolume (PV)。

虽然 Alauda Container Platform 要求 PV 名称唯一,但确保每个导出的 NFS 卷的服务器和路径唯一性仍由管理员负责。

这种分区方式实现了精确的容量管理。开发者请求指定容量(例如 10Gi)的持久存储,ACP 会匹配至少满足该容量的分区/导出支持的 PV。请注意:配额限制适用于分配的分区/导出内的可用存储空间。

NFS 卷安全性

本节介绍 NFS 卷的安全机制,重点是权限匹配。假设读者具备 POSIX 权限、进程 UID 和附加组的基础知识。

开发者通过以下方式请求 NFS 存储:

  • 通过名称引用 PersistentVolumeClaim (PVC),或
  • 在 Pod 规格的 volumes 部分直接配置 NFS 卷插件。

在 NFS 服务器上,/etc/exports 文件定义了可访问目录的导出规则。每个导出目录保留其原生的 POSIX 所有者/组 ID。

Alauda Container Platform 的 NFS 插件关键行为:

  1. 挂载卷到容器时,保留源目录的精确 POSIX 所有权和权限
  2. 运行容器时不强制进程 UID 与挂载所有权匹配——这是有意的安全设计

例如,考虑以下 NFS 目录的服务器端属性:

命令
输出示例
ls -l /share/nfs -d
命令
输出示例
id nfsnobody

此时,容器必须以 UID 65534(nfsnobody 所有者)运行,或在其附加组中包含 5555,才能访问该目录。

NOTE

注意 65534 所有者 ID 仅为示例。尽管 NFS 的 root_squash 会将 root(uid 0)映射为 nfsnobody(uid 65534),但 NFS 导出可以有任意所有者 ID。NFS 导出不必是所有者 65534。

组 ID

推荐的 NFS 访问管理(当导出权限固定时) 当无法修改 NFS 导出的权限时,推荐通过附加组管理访问。

在 Alauda Container Platform 中,附加组是控制共享文件存储(如 NFS)访问的常用机制。

与块存储对比:块存储卷(如 iSCSI)的访问通常通过在 pod 的 securityContext 中设置 fsGroup 实现,该方法依赖挂载时文件系统组所有权的更改。

NOTE

通常建议使用附加组 ID 来访问持久存储,而非使用用户 ID。

由于示例目标 NFS 目录的组 ID 为 5555,pod 可以在其 securityContext 的 supplementalGroups 中定义该组 ID。例如:

spec:
  containers:
    - name:
    ...
  securityContext:
    supplementalGroups: [5555] 
  1. securityContext 必须定义在 pod 级别,而非某个具体容器下。
  2. 定义 pod 的 GID 数组,此处数组中有一个元素,多个 GID 用逗号分隔。

用户 ID

用户 ID 可以在容器镜像中定义,也可以在 Pod 定义中指定。

NOTE

通常建议使用附加组 ID 来访问持久存储,而非使用用户 ID。

在上述示例目标 NFS 目录中,容器需要将其 UID 设置为 65534(暂不考虑组 ID),因此可以在 Pod 定义中添加:

spec:
  containers:
  - name:
  ...
    securityContext:
      runAsUser: 65534
  1. Pod 包含针对每个容器的 securityContext 定义,以及适用于所有容器的 pod 级 securityContext。
  2. 65534 是 nfsnobody 用户。

导出设置

为了允许任意容器用户读写卷,NFS 服务器上的每个导出卷应满足以下条件:

  • 每个导出必须使用如下格式导出:

    # 将 10.0.0.0/24 替换为可信的 CIDRs/主机
    /<example_fs> 10.0.0.0/24(rw,sync,root_squash,no_subtree_check)
  • 防火墙必须配置为允许访问挂载点的流量。

    • 对于 NFSv4,配置默认端口 2049(nfs)。
      iptables -I INPUT 1 -p tcp --dport 2049 -j ACCEPT
    • 对于 NFSv3,需要配置三个端口:2049(nfs)、20048(mountd)和 111(portmapper)。
      iptables -I INPUT 1 -p tcp --dport 2049 -j ACCEPT
      iptables -I INPUT 1 -p tcp --dport 20048 -j ACCEPT
      iptables -I INPUT 1 -p tcp --dport 111 -j ACCEPT
  • NFS 导出和目录必须设置为目标 pod 可访问。要么将导出目录所有权设置为容器的主 UID,要么通过 supplementalGroups 提供 pod 组访问权限,如上文组 ID 所示。

资源回收

NFS 实现了 Alauda Container Platform 的 Recyclable 插件接口。自动流程根据每个持久卷设置的策略处理回收任务。

默认情况下,PV 设置为 Retain。

当 PVC 的声明被删除,且 PV 被释放后,该 PV 对象不应被重复使用。应创建一个新的 PV,基本卷信息与原 PV 相同。

例如,管理员创建了名为 nfs1 的 PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs1
spec:
  capacity:
    storage: 1Mi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.1.1
    path: "/"

用户创建 PVC1,绑定到 nfs1。用户随后删除 PVC1,释放对 nfs1 的声明。此时 nfs1 状态变为 Released。如果管理员想继续使用相同的 NFS 共享,应创建一个新的 PV,使用相同的 NFS 服务器信息,但 PV 名称不同:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs2
spec:
  capacity:
    storage: 1Mi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.1.1
    path: "/"

不建议删除原 PV 后用相同名称重新创建。尝试手动将 PV 状态从 Released 改为 Available 会导致错误和潜在数据丢失。