4.9. 使用 NFS 的持久性存储
OpenShift Container Platform 集群可以使用 NFS 来置备持久性存储。持久性卷 (PV) 和持久性卷声明 (PVC) 提供了在项目间共享卷的方法。虽然 PV 定义中包含的与 NFS 相关的信息也可以直接在 Pod
中定义,但是这样做不会使创建的卷作为一个特定的集群资源,从而可能会导致卷冲突。
其他资源
4.9.1. 置备
当存储可以被挂载为 OpenShift Container Platform 中的卷之前,它必须已存在于底层的存储系统中。要置备 NFS 卷,则需要一个 NFS 服务器和导出路径列表。
流程
为 PV 创建对象定义:
apiVersion: v1 kind: PersistentVolume metadata: name: pv0001 1 spec: capacity: storage: 5Gi 2 accessModes: - ReadWriteOnce 3 nfs: 4 path: /tmp 5 server: 172.17.0.2 6 persistentVolumeReclaimPolicy: Retain 7
注意每个 NFS 卷都必须由集群中的所有可调度节点挂载。
确定创建了 PV:
$ oc get pv
输出示例
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON AGE pv0001 <none> 5Gi RWO Available 31s
创建绑定至新 PV 的持久性卷声明:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-claim1 spec: accessModes: - ReadWriteOnce 1 resources: requests: storage: 5Gi 2 volumeName: pv0001 storageClassName: ""
确认创建了持久卷声明:
$ oc get pvc
输出示例
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-claim1 Bound pv0001 5Gi RWO 2m
4.9.2. 强制磁盘配额
使用磁盘分区强制磁盘配额和大小限制。每个分区都可以有自己的导出。每个导出都是一个 PV。OpenShift Container Platform 会保证每个 PV 都使用不同的名称,但 NFS 卷服务器和路径的唯一性是由管理员实现的。
采用这种方法强制配额可让软件开发人员以特定数量(如 10Gi)请求持久性存储,并可与相等或更大容量的卷进行匹配。
4.9.3. NFS 卷安全
这部分论述了 NFS 卷安全性,其中包括匹配的权限和 SELinux 考虑。用户需要了解 POSIX 权限、进程 UID 、supplemental 组和 SELinux 的基本知识。
软件开发人员可以使用 PVC 名称,或直接在 Pod
定义中 volumes
部分使用 NFS 插件来请求 NFS 存储。
NFS 服务器中的 /etc/exports
文件包含可访问的 NFS 目录。目标 NFS 目录有 POSIX 拥有者和组群 ID。OpenShift Container Platform NFS 插件使用相同的 POSIX 所有者权限及在导出的 NFS 目录中找到的权限挂载容器的 NFS 目录。然而,容器实际运行时所使用的 UID 与 NFS 挂载的所有者的 UID 不同。这是所需的行为。
例如,目标 NFS 目录在 NFS 服务器中,如下所示:
$ ls -lZ /opt/nfs -d
输出示例
drwxrws---. nfsnobody 5555 unconfined_u:object_r:usr_t:s0 /opt/nfs
$ id nfsnobody
输出示例
uid=65534(nfsnobody) gid=65534(nfsnobody) groups=65534(nfsnobody)
为了可以访问目录,容器必须匹配 SELinux 标签,并使用 UID65534
、nfsnobody
的所有者,或其 supplemental 组的 5555
运行。
所有者 ID 65534
只是一个示例。虽然 NFS 的 root_squash
把 root
,uid 0
映射到 nfsnobody
,uid 65534
,但 NFS 导出的所有者 ID 可能是任意值。NFS 导出的所有者不需要是 65534
。
4.9.3.1. 组 ID
用来控制 NFS 访问(假设不能在 NFS 导出中修改权限)的建议方法是使用附加组(supplemental group)。OpenShift Container Platform 中的附件组的功能是用于共享存储(NFS 是一个共享存储)。相对块存储(如 iSCSI),使用 fsGroup
SCC 策略和在 Pod 的 securityContext
中的fsGroup
值。
在访问持久性存储时,一般情况下最好使用 supplemental 组 ID 而不是使用用户 ID。
示例中目标 NFS 目录上的组 ID 是 5555
, Pod 可以使用 Pod 的 securityContext
定义中的 supplementalGroups
来设置组 ID。例如:
spec: containers: - name: ... securityContext: 1 supplementalGroups: [5555] 2
假设没有可能满足 pod 要求的自定义 SCC,pod 可能与受限
SCC 匹配。这个 SCC 把 supplementalGroups
策略设置为 RunAsAny
。这代表提供的任何组群 ID 都被接受,且不进行范围检查。
因此,上面的 pod 可以通过,并被启动。但是,如果需要进行组 ID 范围检查,使用自定义 SCC 就是首选的解决方案。可创建一个定义了最小和最大组群 ID 的自定义 SCC,这样就会强制进行组 ID 范围检查,组 ID 5555
将被允许 。
要使用自定义 SCC,需要首先将其添加到适当的服务帐户(service account)中。例如,在一个特定项目中使用 default
服务账户(除非在 Pod
规格中指定了另外一个账户)。
4.9.3.2. 用户 ID
用户 ID 可以在容器镜像或者 Pod
定义中定义。
通常情况下,最好使用附件组群 ID 而不是用户 ID 来获得对持久性存储的访问。
在上面显示的目标 NFS 目录示例中,容器需要将其 UID 设定为 65534
,忽略组 ID。因此可以把以下内容添加到 Pod
定义中:
spec: containers: 1 - name: ... securityContext: runAsUser: 65534 2
假设项目为 default
且 SCC 为 restricted
,则不允许 pod 请求的用户 ID 65534
。因此,pod 会因以下原因失败:
-
它要求
65534
作为其用户 ID。 -
Pod 可用的所有 SCC 被检查以决定哪些 SCC 允许 ID 为
65534
的用户。虽然检查了 SCC 的所有策略,但这里的焦点是用户 ID。 -
因为所有可用的 SCC 都使用
MustRunAsRange
作为其runAsUser
策略,所以需要进行 UID 范围检查。 -
65534
不包含在 SCC 或项目的用户 ID 范围内。
一般情况下,作为一个最佳实践方案,最好不要修改预定义的 SCC。解决这个问题的的首选方法是,创建一个自定义 SCC,在其中定义最小和最大用户 ID。 UID 范围仍然会被强制检查,UID 65534
会被允许。
要使用自定义 SCC,需要首先将其添加到适当的服务帐户(service account)中。例如,在一个特定项目中使用 default
服务账户(除非在 Pod
规格中指定了另外一个账户)。
4.9.3.3. SELinux
Red Hat Enterprise Linux(RHEL)和 Red Hat Enterprise Linux CoreOS(RHCOS)系统被配置为默认在远程 NFS 服务器中使用 SELinux。
对于非 RHEL 和非 RHCOS 系统,SELinux 不允许从 pod 写入远程 NFS 服务器。NFS 卷正确挂载,但只读。您将需要按照以下步骤启用正确的 SELinux 权限。
先决条件
-
必须安装
container-selinux
软件包。这个软件包提供virt_use_nfs
SELinux 布尔值。
流程
使用以下命令启用
virt_use_nfs
布尔值。使用-P
选项可以使这个布尔值在系统重启后仍然有效。# setsebool -P virt_use_nfs 1
4.9.3.4. 导出设置
为了使任意容器用户都可以读取和写入卷, NFS 服务器中的每个导出的卷都应该满足以下条件:
每个导出必须使用以下格式导出:
/<example_fs> *(rw,root_squash)
必须将防火墙配置为允许到挂载点的流量。
对于 NFSv4,配置默认端口
2049
(nfs)。NFSv4
# iptables -I INPUT 1 -p tcp --dport 2049 -j ACCEPT
对于 NFSv3,需要配置三个端口:
2049
(nfs)、20048
(mountd)和111
(portmapper)。NFSv3
# 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 相关的章节所示)。
4.9.4. 重新声明资源
NFS 实现了 OpenShift Container Platform Recyclable
插件接口。自动进程根据在每个持久性卷上设定的策略处理重新声明的任务。
默认情况下,PV 被设置为 Retain
。
当一个 PVC 被删除后,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 共享变为可用,则应该创建一个具有相同 NFS 服务器详情的新 PV,但使用一个不同的 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
会导致错误并可能造成数据丢失。
4.9.5. 其他配置和故障排除
根据所使用的 NFS 版本以及配置,可能还需要额外的配置步骤来进行正确的导出和安全映射。以下是一些可能适用的信息:
NFSv4 挂载错误地显示所有文件的所有者为 |
|
在 NFSv4 上禁用 ID 映射 |
|