/dev/blog
Bez Hermoso, Software Engineer @ Block
I found myself needing to copy a bunch of files and directories straight from a Docker image. There is a trivial solution in the form of docker cp, but I came up with an alternative using docker run:
$ docker run --rm <IMAGE NAME> \
tar -cf - <SRC_PATH_1> [<SRC_PATH_2> ...] | tar -xvC - <DEST_PATH>
This obviously relies on the the container having
tarinstalled.
This alternative has a few advantages over docker cp:
docker cprequires absolute paths. This supports paths relative to the image’sWORKDIR.docker cpcopies from a container, not an image. This alternative does not require a running container, nor do you need to rundocker createand having to clean it up later (a container is still being created here, but the--rmflag will take care of cleaning it up after use).- You can copy multiple paths in one go.
- You get an progress/activity indicator for free, thanks to the
-vflag in thetarcommand. A list of filenames as they are being extracted to the destination folder.
There is one caveat, however: depending on your image’s configuration, you might encounter this error:
$ docker run --rm ...
tar: Unrecognized archive format
This happens if you have an ENTRYPOINT that is polluting the tar output stream. If you can’t configure your ENTRYPOINT to be completely silent when acting in “bash pass-through mode”, you can chose to just bypass it during docker run execution:
$ docker run --rm --entrypoint= <IMAGE NAME> tar -cf ...
Bonus
This command can potentially produce a ton of output if you are copying a massive amount of files. You can, of course, omit the -v flag from the tar command. However, you can keep the -v flag on but tack this to the end of the command:
2>&1 | while read l; do echo -ne "\033[2K\r$l"; done; echo '...done!'
This reduces the output into a single-line: a “ticker” that displays the filenames as they are being extracted. This way, you don’t lose the perk of having an activity indicator.