在docker中,在容器内创建的文件在从主机检查时往往具有不可预测的所有权。默认情况下,卷上文件的所有者是root(uid 0),但只要非root用户帐户涉及容器并写入文件系统,所有者就会从主机角度变得或多或少随机。 / p>
当您需要使用调用docker命令的同一用户帐户从主机访问卷数据时,会出现问题。
典型的解决方法是
docker run
命令,然后在入口点脚本中的卷上运行一些chown
命令。 这两种解决方案都可以控制容器外的实际权限。
我希望用户名称空间成为此问题的最终解决方案。我已经使用最近发布的版本1.10和--userns-remap设置到我的桌面帐户运行了一些测试。但是,我不确定它是否可以使安装卷上的文件所有权更容易处理,我担心它实际上可能正好相反。
假设我启动这个基本容器
docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit
然后检查主持人的内容:
ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/
-rw-r--r-- 1 100000 100000 6 Feb 8 19:43 test.txt
此号码&#39; 100000&#39;是我的主机用户的子UID,但由于它与我的用户的UID不对应,我仍然无法在没有权限的情况下编辑test.txt。此子用户似乎与docker之外的实际常规用户没有任何关联。它没有映射回来。
由于名称空间中出现UID->sub-UID
映射,本文前面提到的由主机和容器之间的UID对齐组成的变通方法不再起作用。
那么,有没有办法在启用用户名称空间的情况下运行docker(为了提高安全性),同时仍然可以让运行docker的主机用户拥有在卷上生成的文件?
答案 0 :(得分:36)
如果您可以提前预先安排用户和组,则可以以特定方式分配UID和GID,以便主机用户对应容器内的命名空间用户。
以下是一个例子(Ubuntu 14.04,Docker 1.10):
创建一些具有固定数字ID的用户:
useradd -u 5000 ns1
groupadd -g 500000 ns1-root
groupadd -g 501000 ns1-user1
useradd -u 500000 -g ns1-root ns1-root
useradd -u 501000 -g ns1-user1 ns1-user1 -m
在/etc/subuid
和/etc/subgid
个文件中手动修改自动生成的从属ID范围:
ns1:500000:65536
(请注意,由于ns1-root
中的ns1-user1
和MAX_UID
限制,MAX_GID
和/etc/login.defs
没有记录
在/etc/default/docker
中启用用户名称空间:
DOCKER_OPTS="--userns-remap=ns1"
重启守护进程service docker restart
,确保创建/var/lib/docker/500000.500000
目录。
现在,在您拥有root
和user1
的容器内,以及主机上的ns1-root
和ns1-user1
,匹配ID < / p>
更新以保证非root用户在容器中具有固定ID(例如user1 1000:1000),在图像构建期间显式创建它们。
试验驱动器:
准备卷目录
mkdir /vol1
chown ns1-root:ns1-root /vol1
从容器中试用
docker run --rm -ti -v /vol1:/vol1 busybox sh
echo "Hello from container" > /vol1/file
exit
从主持人那里试试
passwd ns1-root
login ns1-root
cat /vol1/file
echo "can write" >> /vol1/file
不便携,看起来像黑客,但有效。
答案 1 :(得分:2)
您可以使用docker cp
command来避免权限问题。
所有权设置为目的地的用户和主要组。例如,复制到容器的文件是使用root用户的
UID:GID
创建的。复制到本地计算机的文件是使用调用UID:GID
命令的用户的docker cp
创建的。
以下示例已切换为使用docker cp
:
$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER VOLUME NAME
local f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct 6 10:34 test.txt
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e33bb735a70f debian:jessie "/bin/bash" About a minute ago Exited (0) About a minute ago determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct 6 10:34 test.txt
$ cat test.txt
hello
$
但是,如果您只想从容器中读取文件,则不需要指定的卷。此示例使用命名容器而不是命名卷:
$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct 6 10:52 test.txt
$ cat test.txt
howdy
$
当我想将文件复制到容器中时,我发现命名卷很有用,如this question中所述。
答案 2 :(得分:1)
一种解决方法是在构建时动态分配用户的uid以匹配主机。
示例Dockerfile
:
FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...
然后将其构建为:
docker build --build-arg UID=$UID -t mycontainer .
并运行为:
docker run mycontainer
如果您已有容器,请使用以下Dockerfile
创建一个包装容器:
FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu
可以将其包装在docker-compose.yml
中,
version: '3.4'
services:
myservice:
command: id
image: myservice
build:
context: .
volumes:
- /data:/data:rw
然后以以下方式构建并运行:
docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice