基于NAS共享NFS的statefulset,volumes绑定为hostpath遇到的权限问题及解决方案。
问题背景:不同于常规k8s的statefulset,我们没有创建pv,在statefulset的yaml文件里没有使用volumeClaimTemplates声明PVC的模板,而是直接使用的volumes搭配hostpath的方式,使用的宿主机的存储卷(宿主机的存储卷目录已经挂载到nas 的nfs共享卷)。statefulset.yaml的volume字段(完整的yaml文件会在文章最末尾贴出来)
问题背景:不同于常规k8s的statefulset,我们没有创建pv,在statefulset的yaml文件里没有使用volumeClaimTemplates声明PVC的模板,而是直接使用的volumes搭配hostpath的方式,使用的宿主机的存储卷(宿主机的存储卷目录已经挂载到nas的nfs共享卷)。
statefulset.yaml的volume字段(完整的yaml文件会在文章附录中贴出来):
apiVersion: apps/v1
kind: StatefulSet
...
volumes:
- name: postgres-volume
hostPath:
path: /mnt
- name: cgwire-volume
hostPath:
path: /mnt
问题描述:我们的实验需要在pod里面启动一个postgresql容器,在postgresql的dockerfile里面需要执行一个指令:
chown -R postgres:postgres /var/lib/postgresql
postgresql想修改挂载目录/mnt里面一个文件的owner和group,但是nfs共享文件夹不让给他权限,pod内的postgresql容器报错:
chown /var/lib/postgresql :Permission denied
以上就是错误信息,我们是用root身份在运行整个流程为什么我们会没有权限执行chown,我们通过命令查看statefulset被调度到的哪个节点,我们去那个节点的挂载目录/mnt下查看文件的所属用户和组,具体如下:
我们可以看到文件的所属用户为nfsnobody,root用户被压缩成了匿名使用者nfsnobody,难怪没有权限,这是怎么回事?我权限呢?通过查询资料我们发现,其实nfs在用户映射方面是有自己的一套操作的,nfs会识别你登陆进nfs的用户信息,是root啊?还是普通用户啊?然后进行映射,映射成nfs内部用户,很显然,我没有进行任何配置映射规则的操作,结果,被nfs映射成了nfsnobody(普通用户,权限最低的普通用户,防止黑客恶意攻击的一种手段)。
知道了原因,我们就可以想办法解决了,通过查询,我们查询到了以下方法:
①挂载时指定mount的版本。
步骤:
加上vers=3,指定使用mount v3 版本进行挂载,例:
mount -t nfs -o vers=3 server:/share /mnt
②修改映射规则。
步骤:
1 先在挂载nfs共享的节点上umount /mnt
umount /mnt
注:如果umount时出现了“device is busy”和“Stale file handle”,点击此链接可能会有帮助。
2 然后在nfs server上修改/etc/exports文件,添加no_root_squash,修改如下:
/mnt *(rw,no_root_squash,sync)
#*的意思是对所有连接过来的用户都执行此操作
分析:
用户对目录的权限受两方面的约束:NFS认证约束、Posix权限
NFS权限:
NFS服务器中的exports中可以配置读写,只读权限。
Posix权限:
exports目录权限中,参数no_root_squash作用是:NFS客户端使用共享目录的用户,如果是root用户的话,所有的操作均在服务端映射为root用户,拥有共享目录的root权限!
默认情况下使用的时相反的参数root_squash:在登入NFS主机的export目录的使用者如果是root时,那么这个使用者的权限将被压缩成匿名使用者,通常他的UID和GID都会变成nobody那个身份(因为之前我们的客户端是用root登录的,自然权限被压缩成nobody了,难怪无法chown)。
3 重新加载业务:
exportfs -arv
4 重新将nfs挂载到/mnt文件夹尝试是否可以chown。
#指定v3的方法
mount -t nfs -o vers=3 server:/share /mnt
例:mount -t nfs -o vers=3 192.168.1.5:/mnt/pool0/hpc /mnt
注:也有可能是selinux的问题
关闭selinux(我是使用的关闭selinux的方法)或者在selinux添加规则,修改挂载目录(我没有做,读者可以自行尝试一下)
关闭selinux:
修改/etc/sysconfig/selinux
SELINUX=disabled
还要临时关闭selinux
setenforce 0
但是,我使用的nas服务器,以上的方法对我的没有权限问题都不奏效,所以说如果写的不到位,还请指教。
在关于nas服务器,我找到了一种解决方法,就是:
这种设置以后,会在nas服务器的/etc/exports文件上追加一条指令。
刚开始是这样:
/mnt/pool0/hpc
修改了映射规则后是这样:
/mnt/pool0/hpc -mapall="root":"wheel"
追加了一条映射指令。
我们重新挂载/mnt,然后常见文件查看nfs文件夹内创建的文件的所属用户和所属组:
我们执行statefulset的yaml文件后,nas上的nfs共享文夹/mnt/pool0/hpc同步过来的文件:
全是root和wheel组,没问题。
节点上挂载nfs的/mnt文件夹内的情况:
没问题,已经修改成了postgres的专属的所属用户,这证明chown也可以使用了。
总结:
最开始介绍的方法,我都用过,但是没有成功,最后的方法是奏效的,可能是TrueNAS有自己的一套开权限的方法吧。
附录:
①完整的statefulset.yaml文件(内含service的yaml文件):
apiVersion: v1
kind: Service
metadata:
name: cgwire
labels:
app: cgwire
spec:
ports:
- port: 80
name: web-service
targetPort: 80
clusterIP: None
selector:
app: cgwire
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-service
spec:
selector:
matchLabels:
app: cgwire
serviceName: "cgwire"
replicas: 1
template:
metadata:
labels:
app: cgwire
spec:
containers:
- name: postgres
image: postgres:latest
imagePullPolicy: IfNotPresent
env:
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
- name: POSTGRES_PASSWORD
value: mysecretpassword
ports:
- containerPort: 5432
name: web-service
volumeMounts:
- name: postgres-volume
mountPath: /var/lib/postgresql/data
- name: cgwire
image: cgwire:latest
imagePullPolicy: Never
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command:
- sh
- -c
- while [ ! -f "/tmp/existed.txt" ];do sleep 8;/opt/zou/init_zou.sh; done
volumeMounts:
- name: cgwire-volume
mountPath: /tmp
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 12
periodSeconds: 3
timeoutSeconds: 3
failureThreshold: 2
volumes:
- name: postgres-volume
hostPath:
path: /mnt/postgres
- name: cgwire-volume
hostPath:
path: /mnt/cgwire
②几个当时我查阅博客,供大家参考。
nfs报错chown changing ownership of xxx Operation not permitted
权限 – 挂载的NFS分区上的chown给出“不允许操作”
NFS服务的用户身份映射
nfs挂载Permission denied问题解决
nfs的配置文件/etc/exports
更多推荐
所有评论(0)