k8s使用PVC挂载mysql数据目录
0X00 Master节点部署nfs-server1.Master节点安装nfs-serverapt install nfs-server2.创建共享目录mkdir /nfs_data3.修改nfs-server共享设置echo "/nfs_data *(rw,sync,no_root_squash)" >> /etc/exports参数作用ro只读rw读写root_squash当NF
0X00 Master节点部署nfs-server
1.Master节点安装nfs-server
apt install nfs-server
2.创建共享目录
mkdir /nfs_data
3.修改nfs-server共享设置
echo "/nfs_data *(rw,sync,no_root_squash)" >> /etc/exports
参数 | 作用 |
---|---|
ro | 只读 |
rw | 读写 |
root_squash | 当NFS客户端以root管理员访问时,映射为NFS服务器的匿名用户 |
no_root_squash | 当NFS客户端以root管理员访问时,映射为NFS服务器的root管理员 |
all_squash | 无论NFS客户端使用什么账户访问,均映射为NFS服务器的匿名用户 |
sync | 同时将数据写入到内存与硬盘中,保证不丢失数据 |
async | 优先将数据保存到内存,然后再写入硬盘;这样效率更高,但可能会丢失数据 |
4.修改目录权限
chmod 666 /nfs_data
5.创建mysql数据目录
mkdir /nfs_data/mysql
6.重启nfs-server
systemctl restart nfs-server
0X01 Node节点部署nfs-common
1.安装nfs-common
apt-get install nfs-common
2.挂载测试
将master节点的共享目录挂载到本地(本地需先创建/nfs_data的空目录)
mount -t nfs MASTER_IP:/nfs_data /nfs_data
3.查看挂载结果
df -h
如果看到远程目录正确挂载了,说明配置成功,可以尝试向目录中写入文件,看是否有权限。
测试完毕后可以删除掉挂载:
umount /nfs_data
0X02 部署mysql并挂载pvc
1.创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: mysql
#mountOptions:
# - hard
# - nfsvers=4.1
nfs:
path: /nfs_data
server: MASTER_IP
kubectl create -f nfs_pv1.yml
查看pv:
kubectl get pv
2.创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc001
spec:
storageClassName: mysql
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kubectl create -f nfs_pvc1.yml
PVC和PV是一对一映射关系,不存在其他关系,只能一对一映射!
3.创建deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: 123456
volumeMounts:
- mountPath: "/var/lib/mysql"
name: mysql-volume
volumes:
- name: mysql-volume
persistentVolumeClaim:
claimName: pvc001
上面的deployment进行的一些设置:
- 使用的镜像版本为mysql:5.7
- 容器暴露端口为3306
- 设置mysql的root用户登录密码为123456
- 挂载pvc001到容器内部的/var/lib/mysql目录
应用deployment:
kubectl create -f mysql-deployment.yml
一些相关命令:
kubectl get deployment # 查看deployment
kubectl get pv # 查看pv
kubectl get pvc # 查看pvc
kubectl delete deployment DEPLOYMENT_NAME # 删除某个deployment,会删除pod,但不会处理pv和pvc
kubectl delete pvc PVC_NAME # 删除PVC
kubectl delete pv PV_NAME # 删除PV,如果PV处于绑定状态则无法删除,进入待删除状态,k8s检测到该PV没有被任何PVC绑定后才会删除
kubectl get pod # 查看pod信息
kubectl logs POD_NAME # 查看某个pod的日志
kubectl describe pod POD_NAME # 查看某个pod的详细信息
0X03 权限问题
1.实验
一开始尝试直接将mysql的数据目录挂载到/nfs_data目录,然后mysql容器就启动失败了,但是该目录明明被授予了666权限:
于是开始解决这个问题,在宿主机上该目录属于root用户,root组,但是权限为666,那么按照道理来说所有用户都是拥有读写权限的,为什么会碰到权限不足的问题?而且在报错之后,该/nfs_data目录居然属于uid 999的用户,但仍然属于root组:
在看了几篇nfs挂载的博客后,发现有人将PV挂载到nfs共享目录的子目录就可以成功,于是我做了以下尝试:
PV挂载目录 | MYSQL_USER | 报错 or 正常 | nfs_data目录属主 | 子文件/目录权限 |
/nfs_data | mysql | mysqld: Can't create/write to file '/var/lib/mysql/is_writable' (Errcode: 13 - Permission denied) | uid 999 group root | 无子目录 |
/nfs_data/mysql | mysql | 正常 | user root group root | uid 999 group docker |
/nfs_data | root | mysqld: Can't create/write to file '/var/lib/mysql/is_writable' (Errcode: 13 - Permission denied) | uid 999 group root | 无子目录 |
/nfs_data/mysql | root | 正常 | user root group root | uid 999 group docker |
从实验结果可以看出,如果直接挂载nfs的共享目录会出现权限问题,而挂载nfs共享目录的子目录是可以成功的,随之而来的是目录权限发生了一些变化。
PS:在实验中为啥有MYSQL_USER这一列呢,因为一开始我在创建mysql-deployment的时候指定了MYSQL_USER环境变量为root,我以为该参数表示在容器内使用root用户启动mysqld进程,但实际上MYSQL_USER参数指的是登录mysql使用的用户(默认使用的为root用户),这个参数对实验没有任何影响,o(╥﹏╥)o
2.分析
首先,在这个实验中出现了多个用户及权限,先捋一下:
- 挂载目录属于的用户,用户组及相关权限(root,root,666)
- mysql容器的用户
- 运行mysqld进程的用户
- 登录mysql的用户
如果能把这些弄清楚,那么权限问题就很明朗了
(1)挂载目录
/nfs_data目录权限不用多说,上面有截图,root用户,root组,666权限
/nfs_data/mysql目录为默认权限,root用户,root组,751
(2)mysql容器的用户
如果不提供任何其他选项,容器中的进程将以root用户身份执行(除非Dockerfile中提供了其他uid),你可以使用以下命令查看容器用户:
docker exec -it CONTAINER_ID "whoami"
可以看到默认mysql容器用户为root
(3)运行mysqld进程的用户
这个又分为容器内进程和宿主机进程:
容器内进程:使用的是mysql用户
宿主机进程:没有用户名,只有uid 999
(4)登录mysql的用户
登录mysql的用户无论为啥都对结果没有影响,所以无所谓了
这个uid 999其实就是容器内部mysql用户的uid,之所以显示uid 999,是因为在宿主机上没有uid 999对应的username。而内核进行权限判定时只针对uid,所以不存在该username也不会存在问题。验证一下,查看容器内的用户和用户组:
至于子文件/目录显示属于docker组也是同理,其实子文件/目录属于的是gid 999的组,但是宿主机上gid 999对应的是docker组,那么就显示的是docker这个groupname了。
3.总结
- 挂载mysql数据目录时,由于mysqld进程要保证拥有目录的读写权限,所以会改变挂载目录属于的用户和用户组,而运行mysqld进程的用户为mysql,所以挂载目录的属主会被改为mysql。
- 普通挂载并不会修改目录权限,修改目录权限是mysqld干的事,并不是docker干的
- 如果挂载目录到容器内部但是容器内部没有读写权限,那肯定是容器内部运行进程的用户没有相关权限造成的,需要修改目录权限。(在容器内外修改都可以,但是建议在容器内部修改)
- 容器是进程级虚拟化,都共享一个内核,只是用了隔离、资源限制技术来对进程进行控制,让容器认为自己运行在独立的环境中
- 容器内部运行某个进程的用户映射到宿主机是根据其uid,username只是一个标识,内核还是根据uid来进行权限判定的。
- 出于安全性考虑,尽量不要在容器内部使用root用户运行进程,否则会映射到宿主机的root用户(因为uid都为0)。推荐做法是在宿主机创建相应用户和用户组,然后容器运行进程时指定uid,这样既可以限制了用户相关权限,又保证了容器进程拥有读写目录的权限。
- 可以通过user namespace技术将容器内的uid 0映射到宿主机其他的uid,而非uid 0,我还没有尝试过
4.遗留问题
权限问题大概了解清楚了,但是还有一个问题没有解决:
为啥不能直接挂载到/nfs_data目录?挂载到其子目录/nfs_data/mysql便可以成功?
按照实验现象来看,推测是修改/nfs_data目录的用户组时失败了,但是具体失败原因目前还不太清楚。(修改属主是成功了的,具体可以看上面表中的测试数据)
0X04 参考资料
理解Docker容器中的uid和gid(英文原版):https://medium.com/@mccode/understanding-how-uid-and-gid-work-in-docker-containers-c37a01d01cf
理解Docker容器中的uid和gid(中文版):https://www.cnblogs.com/sparkdev/p/9614164.html
更多推荐
所有评论(0)