简体   繁体   English

docker cp 后的文件所有权

[英]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 Unix cp -a command in that directories are copied recursively with permissions preserved if possible. cp命令的行为类似于 Unix cp -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 the UID:GID of the user which invoked the docker 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 cptar 流功能:

If - is specified for either the SRC_PATH or DEST_PATH , you can also stream a tar archive from STDIN or to STDOUT .如果为SRC_PATHDEST_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM