k8s使用PVC挂载mysql数据目录

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也不会存在问题。验证一下,查看容器内的用户和用户组:

k8s使用PVC挂载mysql数据目录_第1张图片

至于子文件/目录显示属于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

 

 

 

你可能感兴趣的:(Kubernetes,docker,kubernetes,uid,数据卷,mysql容器)