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)
在将存储作为 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)
1 | 卷的名称。这是各种 oc <command> pod 命令中的 PV 标识。 |
2 | 分配给此卷的存储量。 |
3 | 虽然这似乎与控制对卷的访问有关,但它实际上与标签类似,用于将 PVC 与 PV 匹配。目前,不根据 accessModes 强制执行任何访问规则。 |
4 | 正在使用的卷类型,在本例中为 nfs 插件。 |
5 | NFS 服务器导出的路径。 |
6 | NFS 服务器的主机名或 IP 地址。 |
7 | PV 的回收策略。这定义了释放卷时会发生什么。 |
每个 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: ""
1 | 访问模式不强制执行安全性,而是充当将 PV 与 PVC 匹配的标签。 |
2 | 此声明查找提供 **5Gi** 或更大容量的 PV。 |
验证是否已创建持久卷声明
$ oc get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-claim1 Bound pv0001 5Gi RWO 2m
您可以使用磁盘分区来强制执行磁盘配额和大小限制。每个分区可以是它自己的导出。每个导出是一个 PV。OpenShift Container Platform 强制执行 PV 的唯一名称,但 NFS 卷的服务器和路径的唯一性取决于管理员。
通过这种方式强制执行配额允许开发人员请求特定数量的持久存储,例如 10Gi,并与容量相等或更大的相应卷匹配。
本节介绍 NFS 卷安全性,包括匹配权限和 SELinux 注意事项。预计用户了解 POSIX 权限、进程 UID、补充组和 SELinux 的基础知识。
开发人员通过按名称引用 PVC 或直接在 Pod
定义的 volumes
部分中引用 NFS 卷插件来请求 NFS 存储。
NFS服务器上的/etc/exports
文件包含可访问的NFS目录。目标NFS目录具有POSIX所有者和组ID。OpenShift Container Platform NFS插件以与导出的NFS目录上相同的POSIX所有权和权限挂载容器的NFS目录。但是,容器不会以其有效UID等于NFS挂载点的所有者来运行,这才是理想的行为。
例如,如果目标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标签,并且要么以65534
(nfsnobody
所有者)的UID运行,要么在其补充组中具有5555
才能访问该目录。
所有者ID |
假设无法更改NFS导出的权限,处理NFS访问的推荐方法是使用补充组。OpenShift Container Platform中的补充组用于共享存储,NFS就是一个例子。相比之下,诸如iSCSI之类的块存储使用fsGroup
SCC策略和pod的securityContext
中的fsGroup
值。
为了访问持久性存储,通常最好使用补充组ID而不是用户ID。 |
因为示例目标NFS目录上的组ID是5555
,所以pod可以使用pod的securityContext
定义中的supplementalGroups
定义该组ID。例如:
spec:
containers:
- name:
...
securityContext: (1)
supplementalGroups: [5555] (2)
1 | securityContext 必须在pod级别定义,而不是在特定容器下定义。 |
2 | 为pod定义的GID数组。在本例中,数组中只有一个元素。其他GID将用逗号分隔。 |
假设没有可能满足pod要求的自定义SCC,pod可能匹配restricted
SCC。此SCC将supplementalGroups
策略设置为RunAsAny
,这意味着任何提供的组ID都会被接受,无需范围检查。
因此,上述pod通过准入并启动。但是,如果需要组ID范围检查,则自定义SCC是首选解决方案。可以创建一个自定义SCC,以便定义最小和最大组ID,强制执行组ID范围检查,并允许组ID 5555
。
要使用自定义SCC,必须首先将其添加到相应的服务帐户。例如,除非在 |
用户ID可以在容器镜像或Pod
定义中定义。
通常最好使用补充组ID来访问持久性存储,而不是使用用户ID。 |
在上例所示的目标NFS目录中,容器需要将其UID设置为65534
(暂时忽略组ID),因此可以将以下内容添加到Pod
定义中:
spec:
containers: (1)
- name:
...
securityContext:
runAsUser: 65534 (2)
1 | Pod包含每个容器特有的securityContext 定义以及应用于pod中所有定义的容器的pod的securityContext 。 |
2 | 65534 是nfsnobody 用户。 |
假设项目是default
并且SCC是restricted
,则pod请求的65534
用户ID不被允许。因此,pod由于以下原因而失败:
它请求65534
作为其用户ID。
检查所有可用于pod的SCC,以查看哪个SCC允许用户ID为65534
。虽然会检查所有SCC的策略,但此处重点关注用户ID。
因为所有可用的SCC都对其runAsUser
策略使用MustRunAsRange
,所以需要UID范围检查。
65534
不包含在SCC或项目的用户ID范围内。
通常认为不修改预定义的SCC是一种良好的实践。解决此问题的首选方法是创建一个自定义SCC。可以创建一个自定义SCC,以便定义最小和最大用户ID,仍然强制执行UID范围检查,并允许UID 65534
。
要使用自定义SCC,必须首先将其添加到相应的服务帐户。例如,除非在 |
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
要使任意容器用户能够读取和写入卷,NFS服务器上的每个导出的卷都应符合以下条件:
每个导出都必须使用以下格式导出:
/<example_fs> *(rw,root_squash)
必须配置防火墙以允许访问挂载点的流量。
对于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实现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共享可用,他们应该创建一个新的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
会导致错误和潜在的数据丢失。
根据使用的NFS版本及其配置方式,可能需要其他配置步骤才能进行正确的导出和安全映射。以下是一些可能适用的步骤:
NFSv4挂载错误地显示所有文件的所有者为 |
|
禁用 NFSv4 上的 ID 映射 |
|