docker cp 后的文件所有权
File ownership after docker cp
如何控制哪个用户拥有我复制进出容器的文件?
docker cp
command 关于文件所有权是这样说的:
The cp
command behaves like the Unix cp -a
command in that directories are copied recursively with permissions preserved if possible. 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. Files copied to the local machine are created with the UID:GID
of the user which invoked the docker cp
command. However, if you specify the -a
option, docker cp
sets the ownership to the user and primary group at the source.
它说复制到容器的文件是作为root 用户创建的,但我看到的不是这样。我创建了用户 ID 为 1005 和 1006 的两个文件。这些所有者被转换为容器的用户命名空间。当我将文件复制到容器中时,-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
当我从容器中复制文件时,它们始终归我所有。同样,-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
$
为了完全控制文件所有权,我使用了 docker cp
的 tar stream 功能:
If -
is specified for either the SRC_PATH
or DEST_PATH
, you can also stream a tar archive from STDIN
or to STDOUT
.
我启动 docker cp
进程,然后将 tar 文件流式传输到进程或从进程流出。随着 tar 条目的过去,我可以随心所欲地调整所有权和权限。
这是Python中的一个简单示例,将/outputs
中的所有文件复制到sandbox1
容器中的当前目录,排除当前目录,因此不会获得其权限已更改,并强制所有文件对用户具有 read/write 权限。
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()
除了@Don Kirkby 的回答之外,让我在 bash/shell 脚本中提供一个类似的示例,用于您想要将某些内容复制到容器中同时应用与原始文件不同的所有权和权限的情况.
让我们用一个小图像创建一个新的容器,它将 运行 单独保存:
docker run -d --name nginx nginx:alpine
现在我们将创建一个由当前用户拥有并具有默认权限的新文件:
touch foo.bar
ls -ahl foo.bar
>> -rw-rw-r-- 1 my-user my-group 0 Sep 21 16:45 foo.bar
将此文件复制到容器中会将所有权和组设置为我的用户 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
但是,使用一些 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
选项说明:
c
创建一个新的存档而不是解压一个。
f -
将写入 stdout
而不是文件。
foo.bar
是要打包的输入文件。
--mode
指定目标的权限。类似于chown
,它们可以用符号或八进制数给出。
--owner
设置文件的新所有者。
--group
设置文件的新组。
docker cp -
从 stdin
.
中读取要复制到容器中的文件
当文件需要在启动前复制到创建的容器中时,这种方法很有用,这样 docker exec
不是一个选项(它只能在 运行 容器上运行)。
您还可以通过以 root 用户身份登录容器来更改所有权:
docker exec -it --user root <container-id> /bin/bash
chown -R <username>:<groupname> <folder/file>
只是一行(类似于@ramu 的回答),使用root 来调用:
docker exec -u 0 -it <container-id> chown node:node /home/node/myfile
如何控制哪个用户拥有我复制进出容器的文件?
docker cp
command 关于文件所有权是这样说的:
The
cp
command behaves like the Unixcp -a
command in that directories are copied recursively with permissions preserved if possible. Ownership is set to the user and primary group at the destination. For example, files copied to a container are created withUID:GID
of the root user. Files copied to the local machine are created with theUID:GID
of the user which invoked thedocker cp
command. However, if you specify the-a
option,docker cp
sets the ownership to the user and primary group at the source.
它说复制到容器的文件是作为root 用户创建的,但我看到的不是这样。我创建了用户 ID 为 1005 和 1006 的两个文件。这些所有者被转换为容器的用户命名空间。当我将文件复制到容器中时,-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
当我从容器中复制文件时,它们始终归我所有。同样,-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
$
为了完全控制文件所有权,我使用了 docker cp
的 tar stream 功能:
If
-
is specified for either theSRC_PATH
orDEST_PATH
, you can also stream a tar archive fromSTDIN
or toSTDOUT
.
我启动 docker cp
进程,然后将 tar 文件流式传输到进程或从进程流出。随着 tar 条目的过去,我可以随心所欲地调整所有权和权限。
这是Python中的一个简单示例,将/outputs
中的所有文件复制到sandbox1
容器中的当前目录,排除当前目录,因此不会获得其权限已更改,并强制所有文件对用户具有 read/write 权限。
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()
除了@Don Kirkby 的回答之外,让我在 bash/shell 脚本中提供一个类似的示例,用于您想要将某些内容复制到容器中同时应用与原始文件不同的所有权和权限的情况.
让我们用一个小图像创建一个新的容器,它将 运行 单独保存:
docker run -d --name nginx nginx:alpine
现在我们将创建一个由当前用户拥有并具有默认权限的新文件:
touch foo.bar
ls -ahl foo.bar
>> -rw-rw-r-- 1 my-user my-group 0 Sep 21 16:45 foo.bar
将此文件复制到容器中会将所有权和组设置为我的用户 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
但是,使用一些 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
选项说明:
c
创建一个新的存档而不是解压一个。f -
将写入stdout
而不是文件。foo.bar
是要打包的输入文件。--mode
指定目标的权限。类似于chown
,它们可以用符号或八进制数给出。--owner
设置文件的新所有者。--group
设置文件的新组。
docker cp -
从 stdin
.
当文件需要在启动前复制到创建的容器中时,这种方法很有用,这样 docker exec
不是一个选项(它只能在 运行 容器上运行)。
您还可以通过以 root 用户身份登录容器来更改所有权:
docker exec -it --user root <container-id> /bin/bash
chown -R <username>:<groupname> <folder/file>
只是一行(类似于@ramu 的回答),使用root 来调用:
docker exec -u 0 -it <container-id> chown node:node /home/node/myfile