解决 Docker 持久化数据的权限问题
Docker的数据持久化即数据不随着 container 的结束而结束, 数据存在于 host 机器上: 存在于 host 的某个指定目录中(使用-v
或者--mount
), 或者 docker 自己管理的 volume (Dockerfile 里面设置VOLUME
, 目录在/var/lib/docker/volumes
).
实际使用的时候, 会碰到文件权限的问题:
容器向挂载的目录写入数据后, host 没有权限访问这些数据, 因为容器默认是使用 root 用户运行的(对应 host 的 root 用户).
下面有2种解决方案.
修改 docker 运行用户
这是以前一直用的方法, 需要修改对应的 docker image:
下载 gosu 放到/bin
, 设置一个启动脚本/init.sh
:
#!/bin/bash
if [ ! -f "/tmp/first_run" ]; then
touch /tmp/first_run
PUID=${PUID:-9999}
chown -R $PUID /mnt
useradd -s /bin/bash -u $PUID -o -c "" -m user
usermod -a -G root user
fi
exec /bin/gosu user "$@"
PUID
为 host 用户的 uid
, 这样 容器生成的数据的uid
就和 host 当前用户 一样了, 没有权限问题.
$ docker run --rm -e PUID=$(id -u) -v $PWD:/mnt debian sh -c "touch /mnt/test.log"
缺点
不能使用原始 docker image, 每次都要自己重新修改, 很麻烦.
使用 User Namespace
docker 在1.10
以后加入了这个功能. 使用方式:
开启User Namespace
功能
vim /etc/docker/daemon.json
{
"userns-remap": "fcying"
}
这里表示要将容器中 root 映射到的宿主机用户和用户组, 如果设为 default, docker 会自动创建并映射为 dockremap 用户和用户组.
修改 /etc/subuid
和 /etc/subgid
,建立宿主机用户用户组到容器用户用户组的映射:
vim /etc/subuid
fcying:1000:1
fcying:100001:65536
vim /etc/subgid
fcying:1000:1
fcying:100001:65536
对于subuid
, fcying:1000:1
fcying:100001:65536
表示对于用户 fcying
, 在当前的 user namespace 有 65536个从属用户, 第一个从属用户的uid
设成1000, 这样 容器里面的root
用户对应的宿主机uid
就是fcying(uid:1000)
, 容器里面的其他用户对应的宿主机uid
就是100001~1655365
. 全部用户在容器内部对应的uid
就是0~65535
.
subgid
的含义和subuid
相同.
重启 docker sudo service docker restart
后, 会发现 /var/lib/docker
下多了个1000:1000
目录, 里面的目录结构和/var/lib/docker
一样, 镜像需要重新下载, 这是一个全新的环境. 如果想要回到原先的环境, 关掉 User Namespace
重启 docker
就可以了.
临时禁用User Namespace
使用 --userns=host
docker run --rm --userns=host -v $PWD:/mnt debian sh -c "touch /mnt/test.log"
缺点
目前 docker 对它的支持还算不上完美, 下面是已知的几个和现有功能不兼容的问题:
- 不支持
wsl
- 共享主机的
PID
或NET namespace
(--pid=host
or--network=host
) - 外部的存储 数据卷驱动可能不兼容 不支持
user namespace
- 使用
--privileged
而不指定--userns=host