分析docker启动MySQL挂载目录提示权限不足Permission denied原因

测试如果使用挂载目录不开放目录权限

拉取 MySQL 镜像使用版本8.0.30

docker pull mysql:8.0.30

创建挂载目录文件夹添加自定义配置文件

## 创建挂载目录
[zhangsan@localhost /]$ mkdir -p /home/zhangsan/mysql/{logs,data,conf}

## 创建编辑自定义配置文件
[zhangsan@localhost /]$ vim /home/zhangsan/mysql/conf/my.cnf

## 加入下面内容
[mysqld]
 # 指定数据目录
 datadir=/var/lib/mysql
 # 服务端字符集
 character-set-server=utf8mb4
 # 字符集排序规则
 collation-server=utf8mb4_unicode_ci
 # error日志路径
 log-error=/var/log/mysql/error.log
 # 开启慢查询 1:开启	  【可选】
 slow_query_log=1
 # 定义3秒以上为慢查询	【可选】 
 long_query_time=3
 # 慢查询日志路径		  【可选】	
 slow-query-log-file=/var/log/mysql/slow.log	
[client]
 default-character-set=utf8mb4
[mysql]
 default-character-set=utf8mb4

不开放目录权限直接docker命令启动 MySQL

docker run --name mysql \
-v /home/zhangsan/mysql/data:/var/lib/mysql \
-v /home/zhangsan/mysql/conf:/etc/mysql/conf.d \
-v /home/zhangsan/mysql/logs:/var/log/mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=[密码] \
--net halo-net \
--restart=unless-stopped \
-d mysql:8.0.30

执行 docker ps 查看发现没有启动成功

image-20220804071453043

执行 docker logs [容器ID] 查看错误信息

docker logs a56788d8a9e0

image-20220804071732968

发现出现上述报错提示,无法打开/var/log/mysql/error.log 文件因为权限不足。

网上很多说在启动的时候加上 --privileged=true 赋予docker内容器充分的root权限就可以了,经实测这种启动方式对于centos8 或者 aliyunLinux 是没有效果的而且本质问题也不在于root权限!

初步分析权限不足的原因

执行命令创建临时mysql容器并查询当前容器内mysql目录以及mysql用户权限

docker run -ti --rm  --entrypoint="/bin/bash" mysql:8.0.30 -c "cat /etc/group

image-20220804073030686

docker run -ti --rm  --entrypoint="/bin/bash" mysql:8.0.30 -c "ls -la /var/lib/"

image-20220804073214086

默认docker中使用的是mysql 用户权限,而在docker 容器内环境中mysql用户组id是 999

而宿主机中用户zhangsan的用户组id是1000,所以当挂载目录的时候会提示没有权限,所以解决办法就是将宿主机中对应目录的 [user] [group] [other] 中的[other]一项改成可读可写 rw-

当然最简单的办法是直接授予这个目录777全开放权限(所有人可读可写可执行)

chmod -R 777 /home/zhangsan/mysql

这样宿主机在挂载目录文件的时候就可以了,修改目录权限重新执行后发现mysql已经顺利启动了

当然如果只是这么简单介绍相信各位点进来的技术大佬们要吐槽了,所以我们继续往下探究最小开放目录权限以及为什么会产生这种问题的原因。

详细分析权限不足的原因

1.分析数据目录为什么是属于名为polkitd的用户

查看刚才未修改用户权限时的挂载目录data 它的所属用户是一个叫polkitd的用户???

drwxrwxr-x 6 polkitd            polkitd  4096 Jul 25 12:01 data

大家可能会感到迷惑,为什么这个data目录挂载之后的权限中出现一个polkitd的用户?为什么我用zhangsan账号权限下创建的data目录中会出现其他用户的权限文件?【难道被隔壁老王绿了?🤔】

查看这个polkitd的用户id 貌似有什么惊天发现,

polkitd:x:999:

这个polkitd的用户组id居然是999,相信这个时候已经有不少人反应过来了,这不是容器中mysql的用户组id么?

原因就在这里了,原来在mysql的docker启动文件中指明 可以在启动的时候通过 --user 指定启动用户

# allow the container to be started with `--user`
if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
        _check_config "$@"
        DATADIR="$(_get_config 'datadir' "$@")"
        mkdir -p "$DATADIR"
        chown -R mysql:mysql "$DATADIR"
        exec gosu mysql "$BASH_SOURCE" "$@"
fi

如果不指定则默认使用mysql用户权限,注意上面会使用mysql用户创建数据目录 $DATADIR 然后并授予该目录用户和用户组为mysql 所以当把这个目录挂载出去的时候该目录的用户和用户组是 999 而在宿主机中 999对应的用户是

polkitd,所以说明容器内外对应的用户权限实际使用的是ID 关联而不是用户名。

2.需要修改权限的最小目录范围是什么?

  1. 经过上述分析看出数据目录是容器内mysql启动时用mysql账号权限创建的,所以挂载出来后,通过用户id保持关联,容器内的mysql用户权限目录可以读写宿主机的数据目录
  1. 对于配置文件目录,只要保证在容器内可以读取到宿主机的配置文件即可,通过查看权限发现配置文件权限对于其他用户的策略是可读 r–
  2. 对于日志文件目录,容器内在mysql启动时需要读写宿主机挂载出来的日志文件,通过查看权限发现该文件对于其他用户策略时不可读写的 --x

综上可以看出,最小的目录开放权限就是把日志目录权限改成全开放即可,下面进行实验。

首先使用 docker rm [容器ID] 命令把上面创建成功的docker中的mysql 镜像删除

docker rm a56788d8a9e0

然后把对应挂在的目录也删掉

rm -rf /home/zhangsan/mysql

重新按照上述第一步骤中创建并修改好需要挂在的目录以及自定义配置文件 【见第一步创建挂载目录文件夹添加自定义配置文件】

然后我们只修改logs目录权限

chmod -R 777 /home/zhangsan/mysql/logs

执行启动命令并查看mysql容器是否正常启动

docker run --name mysql \
-v /home/zhangsan/mysql/data:/var/lib/mysql \
-v /home/zhangsan/mysql/conf:/etc/mysql/conf.d \
-v /home/zhangsan/mysql/logs:/var/log/mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=[密码] \
--net halo-net \
--restart=unless-stopped \
-d mysql:8.0.30

发现容器已经正常启动了,进入容器也没有问题👌。

所以如果你不想挂载日志目录的话,单纯挂载数据目录是不需要修改权限的。但是为了查看日志方便还是推荐挂载到自定义的目录中,方便查看错误日志或者慢查询日志。

3.补充:通过指定启动容器时的用户避免修改目录权限

如果想挂载日志目录但不想修改目录权限也有办法:

第1步分析中可以在启动时指定容器启动的用户权限,但要注意传递的是用户的ID号,如果把zhangsan的用户号1000通过启动参数 – user:1000 传入则容器内的mysql创建者就不再是默认ID 号为999的mysql用户了,这样挂载出来的时候对应的1000用户号就是你当前的用户zhangsan,这样挂载目录所有者为zhangsan,当然就不会出现读取目录文件时用户权限不足的问题了。

命令如下:

docker run --name mysql \
-- user 1000
-v /home/zhangsan/mysql/data:/var/lib/mysql \
-v /home/zhangsan/mysql/conf:/etc/mysql/conf.d \
-v /home/zhangsan/mysql/logs:/var/log/mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=[密码] \
--net halo-net \
--restart=unless-stopped \
-d mysql:8.0.30

启动成功后查看对应的目录权限:

drwxrwxr-x 2 zhangsan           zhangsan 4096 Jul 25 11:43 conf
drwxrwxr-x 6 zhangsan           zhangsan 4096 Jul 25 12:01 data
drwxrwxrwx 2 zhangsan           zhangsan 4096 Jul 25 11:47 logs

此时发现对应的data已经变成zhangsan了启动也正常,至此权限不足的问题就解决了。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐