解决docker容器的目录权限的总结

背景

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
mysql:
restart: always
image: mysql:5.7.23
container_name: mysql
ports:
- 3306:3306
volumes:
- ./conf:/etc/mysql/conf.d
- ./logs:/var/log/mysql
- ./data:/var/lib/mysql

部署mysql的时候,将mysql目录进行挂载时提示

1
cannot read directory '/var/lib/mysql/': Permission denied

原因

我们聚集到entrypoint.sh这个文件,因为docker的镜像变成运行态的时候,也就是容器的时候,是需要命令来启动的,这个启动的命令就是entrypoint.sh,也就是说,启动的这个文件肯定是篡改了原来的目录,下面具体看下这个文件的某个关键代码片段

1
2
3
4
5
6
7
8
# 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用户来执行脚本,所以实际上,用户就变mysql了,但是为啥在宿主机上,却是polkitd呢?

F5qwr7

1
2
// 容器内查看用户名为`mysql` 对应的用户ID和组ID为`999`
cat /etc/passwd | grep mysql

WlHpMT

1
2
// 宿主机器查看999所对应的用户名
cat /etc/passwd | grep 999

如上图,可以看到,在容器内部,他的用户为mysql,他的用户ID为999,然后退出容器,在宿主机上,可以看到ID为999的用户ID对应的用户变成了polkitd,所以,到了这里就明白了,实际上容器内部和外部是用的同一套用户,名字可能不同,但是ID用的是同一个,从而导致,ID虽然相同,但是用户不一致,从而权限也出现了差别。

1、其实在操作系统中,真正决定用户和用户组的东西并不是用户名和组名,而是相应的用户id 和 对应的组id,当我们刚创建用户时系统就会给用户分配对应的用户id 和 组id,可以在/etc/passwd中查看

2、在遇到的问题描述中,因为容器中只创建了一个mysql用户和组,因此容器中查看到mysql用户id和组id为999:999,因此给/var/lib/mysql目录用户权限时其实是给予的用户id和组id为999:999权限,因此,在宿主机中./data此目录的用户权限也变为999:999,因为宿主机中此用户id和组id对应的为polkitd,因此就显示为polkitd。

解决

方法1 推荐

在配置my.cnf时,指定error-log的位置在/var/log/下,否则error的默认位置为例如/var/lib/mysql下的mysqld.log文件因为目录映射后有权限问题,写入不了日志。

方法2

宿主机器更改与docker相同的用户ID和组id
chown 999

方法3

同步宿主/etc/passwd到容器内,从而达到宿主和容器内相同的用户id和组ID

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# getenforce
Enforcing
[root@localhost ~]# setenforce 0
[root@localhost ~]# getenforce
Permissive
[root@localhost ~]# systemctl restart docker
[root@localhost ~]# vi /etc/selinux/config
#修改 SELINUX=disabled
[root@localhost ~]# init 6
#重启系统

实验

一直以来比较困惑容器挂载卷的文件权限问题,今天特地梳理下docker的挂载卷权限问题

首先,本地挂载点新建测试文件test.txt,然后将该目录挂载到容器的test目录
e7n7BA
可以看到我们在容器外新建的test.txt文件在容器内的所有者变成了1000,然后我们在容器内新建文件查看容器外的权限,发现容器中新建的test1.txt所有者变成了root
AfaH0v

接着查看下UID:1000所属用户
olz9nC
最后我们在指定wag用户启动docker,然后在容器内新建test3.txt文件,查看文件所有者
4fr3ct

从以上可以得出,docker启动容器如果不指定用户,会默认以root(UID=0)方式运行,导致其中新建的文件所有者映射到容器外为root,容器外新建的文件映射到容器内所有者UID不变。