File ownership after docker cp

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 to stdout instead of a file.
  • foo.bar is the input file to be packed.
  • --mode specifies the permissions for the target. Similar to chown, 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).


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

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>

In order to get complete control of file ownership, I used the tar stream feature of docker cp:

If - is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT.

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()