I'd like to extract a file from a Docker image without having to run the image.
The docker save
option is not currrently a viable option for me as it's saving too huge of a file just to un-tar a specific file.
You can extract files from an image with the following commands:
container_id=$(docker create "$image")
docker cp "$container_id:$source_path" "$destination_path"
docker rm "$container_id"
According to the docker create
documentation, this doesn't run the container:
The
docker create
command creates a writeable container layer over the specified image and prepares it for running the specified command. The container ID is then printed toSTDOUT
. This is similar todocker run -d
except the container is never started. You can then use thedocker start <container_id>
command to start the container at any point.
For reference (my previous answer), a less efficient way of extracting a file from an image is the following:
docker run some_image cat "$file_path" > "$output_path"
None of the above worked for me. The complete working command is:
docker run --rm --entrypoint /bin/sh image_name -c "cat /path/filename" > output_filename
Without quotes cat
is passed without filename, so it does not know what to show. Also it is a good idea to delete the container after command is finished.
docker run --rm --entrypoint /bin/cat image_name /path/filename > output_filename
– Beni Cherniavsky-Paskin
Jun 25 '20 at 21:21
docker run --entrypoint /bin/cat image_name /path/filename > filename
– lauksas
Sep 09 '21 at 17:03
cat
and /path/filename
are in different places, but they work together. Also without --rm
you leave some junk on disk until you prune docker explicitly.
– sekrett
Oct 20 '22 at 10:26
If storing the full output of docker save
isn't an option, you could use pipelines to extract just the needed file from it.
Unfortunately, because the output is a "tar of tars", it can be a slightly iterative process.
What I did when I needed to extract a file just now was:
Determine which version of the image the file you are interested in changed most recently (how you do this probably depends on your image), and the date it was created / saved
Get the full table of contents from the output of the docker save
command with:
docker save IMAGE_NAME | tar -tvf -
Find the layer.tar
file(s) in the output of that command that match the date of the image that you determined in step 1. (you can add | grep layer.tar
to just show those files)
Extract that layer.tar
file to standard out, and get the table of contents of it:
docker save IMAGE_NAME | tar -xf - -O CHECKSUM_FROM_LIST/layer.tar | tar -tvf -
Verify the file you want is listed, and extract it once you find the name:
docker save IMAGE_NAME | tar -xf - -O CHECKSUM_FROM_LIST/layer.tar | tar -xf - PATH/TO/YOUR/FILE
If there are more than one layer.tar
files matching the date you are looking for in step 2/3, you may need to repeat step 4 for each one of them until you find the right one
Replace the text in capitals in the commands above with the correct image names, checksums and filenames for your case.
I believe that Docker containers store cached files created in the following directory for Ubuntu:
/var/lib/docker/aufs/diff/<container_id>
From there you should be able to access the file system and retrieve your file(s).
layersize
and json
, and is also not user readable (even if user is in docker group). /var/lib/docker/aufs/diff
will contain the file that I look for (but is categorized not by container id) and is also not readable.
– BlakBat
Dec 20 '16 at 16:24
/var/lib/docker/aufs
(but not all other directories in /var/lib/docker/
)
– BlakBat
Dec 21 '16 at 09:46
docker info
to check).
– Beni Cherniavsky-Paskin
Jun 25 '20 at 21:20
Here is another option which does not even create the container and avoids fiddling with the layers manually, but may act funny if multiple layers contain some of the files you're interested in:
$ docker image save IMAGE_NAME | tar --extract --wildcards --to-stdout '*/layer.tar' | tar --extract --ignore-zeros --verbose FILE_OR_DIRECTORY
docker run --entrypoint /bin/sh my_image -c /bin/cat some_file
– Andrew Jun 06 '18 at 23:52docker create image
,docker cp container:/file_path /output_path
but that doesn't seem to actually work unless you also dodocker start container
before thecp
, which likely runs the container. – bbc Mar 26 '19 at 17:37docker start
, it's probably not needed. I'll update my answer accordingly. – bbc Apr 16 '19 at 11:51jvm.options
from the elasticsearch-docker. This small script will get the latest version:CONTAINER_ID=$(docker create $(docker image ls | awk '$1 ~ /\/elasticsearch-docker/ { print $2, $3 }' | sort -V | tail -1 | awk '{ print $2 }')) ; docker cp ${CONTAINER_ID}:/usr/share/elasticsearch/config/jvm.options /tmp/jvm.options ; docker rm ${CONTAINER_ID}
. – sastorsl Mar 11 '20 at 08:42Error response from daemon: No command specified
In this case, add a dummy command after the image name. It can bedummycommand
or any made up gibberish, since it won't actually be run. – PolyTekPatrick Dec 08 '21 at 05:24