依旧是工作中遇到的问题,熬夜解决了,写博客记录下。
场景描述
甲方生产环境使用 k8s 部署两家乙方的服务,甲方在集群物理机上为两个乙方创建了用户(user_a,user_b)和各自的磁盘目录(share_a,share_b)。现在因为业务需求,两个用户需要在 share_a 目录下创建子目录并将各自服务的输出保存的到其中,子目录的名称两个乙方约定好,并且谁先用到谁创建,子目录区权限775,不然一个创建了目录,另一个没写权限。好死不死,我们是 user_b。
解决思路
原本 dev,愣是干成了 ops,好在问题不大,外加自己头铁,研究研究…。
- 容器肯定要挂载 share_a 目录,服务中通过代码创建 775 权限的子目录。这个问题已经搞定了。
- 容器肯定不能以 root 权限运行,因为谁创建谁是 owner。所以必须以 user_b 用户运行。
- 因为是 775 权限,所以 user_a 和 user_b 必须是同组用户,不然也是没有写权限的。
总结:构建镜像时创建两个用户 user_a ,user_b 并将后者加入前者的 groups 中,因为要在人家的目录下干活。
原型测试
1.在物理机上创建两个用户,分别加入对方用户组中。再分别为两个用户创建各自的磁盘目录,将目录设置成 775 权限。两用户都对对方磁盘目录有读写权限。
sudo useradd user_a -u 2341 # 创建用户时会以用户名为组名同时创建用户组。
sudo passwd user_a # 设置密码,不然没法切换用户。
su user_a # 输入密码切换用户。
mkdir -p /tmp/user_a # 为 user_a 用户创建磁盘
sudo useradd user_b -u 2381
sudo passwd user_b
su user_b
mkdir -p /tmp/user_b
sudo usermod -a -G user_a user_b # 用户:user_b 加入用户组:user_a
sudo usermod -a -G user_b user_a #
结果:
# 查看磁盘目录
ll /tmp
drwxrwxr-x 2 user_a user_a 6 Aug 18 18:07 user_a
drwxrwxr-x 2 user_b user_b 6 Aug 19 11:27 user_b
# 查看用户
cat /etc/passwd
user_a:x:2341:2341::/home/user_a:/bin/bash
user_b:x:2381:2381::/home/user_b:/bin/bash
# 查看用户所属组
groups user_a
user_a : user_a user_b
groups user_b
user_b : user_b user_a
物理机上的场景就算是构建出来了。 a,b 两用户都可以写对方的磁盘目录。
2.再构建容器内部的场景,其实和物理机是一样的,创建两个用户并互加组再挂在磁盘目录。
(1)创建 Dockerfile
FROM spack/centos7:v0.18.0 # 这个随便找的
RUN adduser user_a -u 2341 \
&& adduser user_b -u 2381 \
&& usermod -a -G user_a user_b
WORKDIR /home/user_b
(2) deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-b
labels:
app: user-b
spec:
selector:
matchLabels:
app: user-b
template:
metadata:
labels:
app: user-b
spec:
securityContext:
runAsUser: 2381 # 设置容器内当前用户为 user_b
nodeSelector:
kubernetes.io/hostname: sh02 # 因为是测试,将 pod 调度到指定的物理机上。
containers:
- image: yang:01
name: user-b
command: ["sleep"]
args: ["infinity"]
volumeMounts:
- name: a
mountPath: /home/user_b/dir_a
- name: b
mountPath: /home/user_b/dir_b
volumes:
- name: a
hostPath:
path: /tmp/user_a # 挂载 user_a 的磁盘目录
- name: b
hostPath:
path: /tmp/user_b # 挂载 user_b 的磁盘目录
容器启动后查看:
[user_b@user-b-9cd656cb4-46fc6 ~]$ whoami
user_b
[user_b@user-b-9cd656cb4-46fc6 ~]$ pwd
/home/user_b
[user_b@user-b-9cd656cb4-46fc6 ~]$ ll ./
total 0
drwxrwxr-x 2 user_a user_a 40 Aug 19 07:23 dir_a
drwxrwxr-x 2 user_b user_b 6 Aug 19 07:09 dir_b
磁盘上两个目录挂载进来了,而且目录的权限和所属用户与原来状况一致。
当前用户 user_b 向 dir_a 中写文件:
[user_b@user-b-9cd656cb4-46fc6 ~]$ touch dir_a/file-created-by_user_b.txt
[user_b@user-b-9cd656cb4-46fc6 ~]$ ll dir_a/
total 0
-rw-rw-r-- 1 user_b user_b 0 Aug 19 07:23 file-created-by_user_b.txt
最后在物理机的磁盘上查看
(base) [deployer@sh02 yang]$ ll /tmp/user_a/
total 0
-rw-rw-r-- 1 user_b user_b 0 Aug 19 15:23 file-created-by_user_b.txt
写入成功。
小细节
上面 yaml 将磁盘目录挂载到容器中,并且磁盘目录的权限保持不变,必须要求磁盘目录(/tmp/user_a)是真实存在的。如果将一个不存在的磁盘目录挂载到容器中,在 pod 启动时 k8s 会在物理机上递归创建该目录,由于 k8s 是以 root 权限运行的,所以该目录的 owner 是 root 且 755 权限。此时因为 user_b 不在 root 用户组里,所以没有写权限。
不存在的目录:/tmp/user_a/not_exist
containers:
- image: yang:01
name: user-b
command: ["sleep"]
args: ["infinity"]
volumeMounts:
- name: a
mountPath: /home/user_b/dir_a
volumes:
- name: a
hostPath:
path: /tmp/user_a/not_exist
pod 启动后进入容器查看
[user_b@user-b-5c6dbcd55c-dfs6b ~]$ ll
total 0
drwxr-xr-x 2 root root 6 Aug 19 07:48 dir_a
[user_b@user-b-5c6dbcd55c-dfs6b ~]$ touch dir_a/file-created-by_user_b.txt
touch: cannot touch 'dir_a/file-created-by_user_b.txt': Permission denied
权限不够,甭想写。