使用 NFS 配置持久存储

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

目录

前提条件

  • 底层基础设施中必须存在存储,才能在 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 替换为可信任的 CIDR 或主机
    /<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 会导致错误和潜在数据丢失。