How to access files in a docker container built on scratch

09.06.2020
Martin Friedel
docker

We love using go to build our backend services. Among many reasons one is the fact that when you build your application into a docker image, it contains literally nothing except your application. Many other languages or frameworks require a complete linux to be packaged into the container (or even a virtual machine running on a linux!), making it bigger and more complex.

Tiny blackbox?

While we find it very awesome when our build pipeline spits out a 6mb docker image that contains basically an executable and a folder with some compiled HTML/CSS/JS initially there seems to be a downside: You cannot get at the contents of the running container as easily as when you can actually connect with a shell into the container. You see it is running in a docker ps but it's a bit of a black box. Of course you can mount volumes to have the application store information outside the container, but you may have forgotten to do so and now some bit of information is locked up in there? Worry not, there is a way to get at it.

Lets say our server generates a pdf file with a name based on a timestamp (so we do not know the name). The container is running, the pdf is saved inside the containers filesystem. Now we want to get it out for inspection.

So first we need to know the id of the container. So we run docker ps to get our container id. Say it is "8f87b75b584e".

Docker export to the rescue

Docker supports a command that will take the filesystem of a container and export it to STDOUT. This is useful for instance to export the filsystem from inside a container into a tar file:

docker export 8f87b75b584e > my_container.tar

You can also use it to export the filesystem into the tar executable to output what files are contained inside like so:

 docker export 8f87b75b584e | tar t

This will output something like the following:

.dockerenv
app/
app/server
app/documents/1590404561193689502.pdf
app/public/
app/public/assets/favicon.ico
app/public/assets/logo.svg
app/public/index.html
app/public/static/
app/public/static/css/
app/public/static/css/main.5de28820.chunk.css
app/public/static/css/main.5de28820.chunk.css.map
app/public/static/js/
app/public/static/js/2.20a9197e.chunk.js
app/public/static/js/2.20a9197e.chunk.js.LICENSE.txt
app/public/static/js/2.20a9197e.chunk.js.map
app/public/static/js/main.c34e0be6.chunk.js
app/public/static/js/main.c34e0be6.chunk.js.map
app/public/static/js/runtime-main.7eede39e.js
app/public/static/js/runtime-main.7eede39e.js.map
dev/
dev/console
dev/pts/
dev/shm/
etc/
etc/hostname
etc/hosts
etc/mtab
etc/resolv.conf
proc/
sys/

So now we know what it is called: 1590404561193689502.pdf That makes it possible to copy the file from the running docker container to the hosts filesystem:

docker cp 8f87b75b584e:app/documents/1590404561193689502.pdf test.pdf

Voila! Having these tools at hand takes away what might otherwise be a drawback to the ultra lean docker images possible when packaging a go application in an image based on "scratch".