File ownership after docker cp
Solution 1
In order to get complete control of file ownership, I used the tar stream feature of docker cp
:
If
-
is specified for either theSRC_PATH
orDEST_PATH
, you can also stream a tar archive fromSTDIN
or toSTDOUT
.
I launch the docker cp
process, then stream a tar file to or from the process. As the tar entries go past, I can adjust the ownership and permissions however I like.
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.
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()
Solution 2
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.
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:
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 -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:
-
c
creates a new archive instead of unpacking one. -
f -
will write tostdout
instead of a file. -
foo.bar
is the input file to be packed. -
--mode
specifies the permissions for the target. Similar tochown
, they can be given in symbolic notation or as an octal number. -
--owner
sets the new owner of the file. -
--group
sets the new group of the file.
docker cp -
reads the file that is to be copied into the container from 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).
Solution 3
You can also change the ownership by logging in as root user into the container :
docker exec -it --user root <container-id> /bin/bash
chown -R <username>:<groupname> <folder/file>
Solution 4
Just a one-liner (similar to @ramu's answer), using root to make the call:
docker exec -u 0 -it <container-id> chown node:node /home/node/myfile
Related videos on Youtube
Don Kirkby
Python, Java, and C# developer working in AIDS research. Hobbies include designing board games and puzzles, as well as learning Chinese. If you just want to see the codez, check out GitHub. To contact me, use Twitter or e-mail [email protected] .
Updated on September 16, 2022Comments
-
Don Kirkby over 1 year
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: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.It says that files copied to a container are created as the root user, but that's not what I see. I create two files owned by user id 1005 and 1006. Those owners are translated into the container's user namespace. The
-a
option seems to make no difference when I copy the file into a container.$ 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.$ 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 $
-
MadMike about 4 yearsI had trouble using a non-root user within the docker-container. I've solved this by listing the file in the container with '-n', thus 'docker exec nginx sh -c 'ls -ahln /foo.bar' and using the number on the tar parameter, thus 'tar -cf - foo.bar --mode u=+r,g=-rwx,o=-rwx --owner 1000 --group 1000 | docker cp - nginx:/'
-
Oli Girling over 2 yearsWorked for me! Thanks