[英]File ownership after docker cp
How can I control which user owns the files I copy in and out of a container?如何控制哪个用户拥有我复制进和复制出容器的文件?
The docker cp
command says this about file ownership: docker cp
命令说明了文件所有权:
The
cp
command behaves like the Unixcp -a
command in that directories are copied recursively with permissions preserved if possible.cp
命令的行为类似于 Unixcp -a
命令,因为目录被递归复制,并尽可能保留权限。 Ownership is set to the user and primary group at the destination.所有权设置为目的地的用户和主要组。 For example, files copied to a container are created with
UID:GID
of the root user.例如,复制到容器的文件是使用 root 用户的
UID:GID
创建的。 Files copied to the local machine are created with theUID:GID
of the user which invoked thedocker cp
command.复制到本地机器的文件是使用调用
docker cp
命令的用户的UID:GID
创建的。 However, if you specify the-a
option,docker cp
sets the ownership to the user and primary group at the source.但是,如果您指定
-a
选项,则docker cp
所有权设置为源中的用户和主要组。
It says that files copied to a container are created as the root user, but that's not what I see.它说复制到容器的文件是作为 root 用户创建的,但这不是我看到的。 I create two files owned by user id 1005 and 1006. Those owners are translated into the container's user namespace.
我创建了用户 ID 1005 和 1006 拥有的两个文件。这些所有者被转换为容器的用户命名空间。 The
-a
option seems to make no difference when I copy the file into a container.当我将文件复制到容器中时,
-a
选项似乎没有任何区别。
$ sudo chown 1005:1005 test.txt
$ ls -l test.txt
-rw-r--r-- 1 1005 1005 29 Oct 6 12:43 test.txt
$ docker volume create sandbox1
sandbox1
$ docker run --name run1 -vsandbox1:/data alpine echo OK
OK
$ docker cp test.txt run1:/data/test1005.txt
$ docker cp -a test.txt run1:/data/test1005a.txt
$ sudo chown 1006:1006 test.txt
$ docker cp test.txt run1:/data/test1006.txt
$ docker cp -a test.txt run1:/data/test1006a.txt
$ docker run --rm -vsandbox1:/data alpine ls -l /data
total 16
-rw-r--r-- 1 1005 1005 29 Oct 6 19:43 test1005.txt
-rw-r--r-- 1 1005 1005 29 Oct 6 19:43 test1005a.txt
-rw-r--r-- 1 1006 1006 29 Oct 6 19:43 test1006.txt
-rw-r--r-- 1 1006 1006 29 Oct 6 19:43 test1006a.txt
When I copy files out of the container, they are always owned by me.当我从容器中复制文件时,它们始终归我所有。 Again, the
-a
option seems to do nothing.同样,
-a
选项似乎什么都不做。
$ docker run --rm -vsandbox1:/data alpine cp /data/test1006.txt /data/test1007.txt
$ docker run --rm -vsandbox1:/data alpine chown 1007:1007 /data/test1007.txt
$ docker cp run1:/data/test1006.txt .
$ docker cp run1:/data/test1007.txt .
$ docker cp -a run1:/data/test1006.txt test1006a.txt
$ docker cp -a run1:/data/test1007.txt test1007a.txt
$ ls -l test*.txt
-rw-r--r-- 1 don don 29 Oct 6 12:43 test1006a.txt
-rw-r--r-- 1 don don 29 Oct 6 12:43 test1006.txt
-rw-r--r-- 1 don don 29 Oct 6 12:47 test1007a.txt
-rw-r--r-- 1 don don 29 Oct 6 12:47 test1007.txt
-rw-r--r-- 1 1006 1006 29 Oct 6 12:43 test.txt
$
In addition to @Don Kirkby's answer, let me provide a similar example in bash/shell script for the case that you want to copy something into a container while applying different ownership and permissions than those of the original file.除了@Don Kirkby 的回答之外,让我在 bash/shell 脚本中提供一个类似的示例,用于将某些内容复制到容器中,同时应用与原始文件不同的所有权和权限的情况。
Let's create a new container from a small image that will keep running by itself:让我们从一个小镜像创建一个新的容器,它会继续自己运行:
docker run -d --name nginx nginx:alpine
Now wel'll create a new file which is owned by the current user and has default permissions:现在我们将创建一个由当前用户拥有并具有默认权限的新文件:
touch foo.bar
ls -ahl foo.bar
>> -rw-rw-r-- 1 my-user my-group 0 Sep 21 16:45 foo.bar
Copying this file into the container will set ownership and group to the UID
of my user and preserve the permissions:将此文件复制到容器中会将所有权和组设置为我的用户的
UID
并保留权限:
docker cp foo.bar nginx:/foo.bar
docker exec nginx sh -c 'ls -ahl /foo.bar'
>> -rw-rw-r-- 1 4098 4098 0 Sep 21 14:45 /foo.bar
Using a little tar
work-around, however, I can change the ownership and permissions that are applied inside of the container.但是,使用一点
tar
变通方法,我可以更改应用于容器内部的所有权和权限。
tar -cf - foo.bar --mode u=+r,g=-rwx,o=-rwx --owner root --group root | docker cp - nginx:/
docker exec nginx sh -c 'ls -ahl /foo.bar'
>> -r-------- 1 root root 0 Sep 21 14:45 /foo.bar
tar
options explained: tar
选项解释:
c
creates a new archive instead of unpacking one. c
创建一个新存档而不是解压一个存档。f -
will write to stdout
instead of a file. f -
将写入stdout
而不是文件。foo.bar
is the input file to be packed. foo.bar
是要打包的输入文件。--mode
specifies the permissions for the target. --mode
指定目标的权限。 Similar to chown
, they can be given in symbolic notation or as an octal number.chown
类似,它们可以用符号表示法或八进制数给出。--owner
sets the new owner of the file. --owner
设置文件的新所有者。--group
sets the new group of the file. --group
设置文件的新组。 docker cp -
reads the file that is to be copied into the container from stdin
. docker cp -
从stdin
读取要复制到容器中的文件。
This approach is useful when a file needs to be copied into a created container before it starts, such that docker exec
is not an option (which can only operate on running containers).当文件需要在启动之前复制到创建的容器中时,这种方法很有用,这样
docker exec
不是一个选项(只能对正在运行的容器进行操作)。
You can also change the ownership by logging in as root user into the container :您还可以通过以 root 用户身份登录容器来更改所有权:
docker exec -it --user root <container-id> /bin/bash
chown -R <username>:<groupname> <folder/file>
In order to get complete control of file ownership, I used the tar stream feature of docker cp
:为了完全控制文件所有权,我使用了
docker cp
的tar 流功能:
If
-
is specified for either theSRC_PATH
orDEST_PATH
, you can also stream a tar archive fromSTDIN
or toSTDOUT
.如果为
SRC_PATH
或DEST_PATH
指定了-
,您还可以将 tar 存档从STDIN
流式传输到STDOUT
。
I launch the docker cp
process, then stream a tar file to or from the process.我启动
docker cp
进程,然后将 tar 文件docker cp
该进程。 As the tar entries go past, I can adjust the ownership and permissions however I like.随着 tar 条目过去,我可以随意调整所有权和权限。
Here's a simple example in Python that copies all the files from /outputs
in the sandbox1
container to the current directory, excludes the current directory so its permissions don't get changed, and forces all the files to have read/write permissions for the user.这是 Python 中的一个简单示例,
sandbox1
容器中的/outputs
中的所有文件复制到当前目录,排除当前目录使其权限不会更改,并强制所有文件具有用户的读/写权限.
from subprocess import Popen, PIPE, CalledProcessError
import tarfile
def main():
export_args = ['sudo', 'docker', 'cp', 'sandbox1:/outputs/.', '-']
exporter = Popen(export_args, stdout=PIPE)
tar_file = tarfile.open(fileobj=exporter.stdout, mode='r|')
tar_file.extractall('.', members=exclude_root(tar_file))
exporter.wait()
if exporter.returncode:
raise CalledProcessError(exporter.returncode, export_args)
def exclude_root(tarinfos):
print('\nOutputs:')
for tarinfo in tarinfos:
if tarinfo.name != '.':
assert tarinfo.name.startswith('./'), tarinfo.name
print(tarinfo.name[2:])
tarinfo.mode |= 0o600
yield tarinfo
main()
只是一个单行(类似于@ramu 的回答),使用root拨打电话:
docker exec -u 0 -it <container-id> chown node:node /home/node/myfile
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.