13

I have a simple Dockerfile which creates a zip file and I'm trying retrieve the zip file once it is ready. My Dockerfile looks like this:

FROM ubuntu

RUN apt-get update && apt-get install -y build-essentials gcc

ENTRYPOINT ["zip","-r","-9"]
CMD ["/lib64.zip", "/lib64"]

After reading through the docs I fee like something like this should do it but I can't quite get it to work.

docker build -t ubuntu-libs .
docker run -d --name ubuntu-libs --mount source=$(pwd)/,target=/lib64.zip ubuntu-libs

One other side question: Is is possible to rename the zip file from the command line?

Edit:

This is different than the duplicate question mentioned in the comments because while they're using cp to copy file from a running Docker container I'm trying to mount a directory upon instantiation.

Pardoner
  • 1,011
  • 4
  • 16
  • 28
  • you are mapping a directory of the host to a file in the container? try mounting directory to directory, and create the zip inside that directory, it should work (also, does 'apt-get install -y' do anything without a package name?) – flagg19 Jun 27 '19 at 19:38
  • @flagg Am I not mapping the root (/) with the current working directory (pwd)? You're right that should be `apt-get install -y build-essentials gcc` – Pardoner Jun 27 '19 at 19:46
  • I'm not really experienced with the --mount command (I usually use --volume) but looking at the documentation https://docs.docker.com/engine/reference/commandline/service_create/#add-bind-mounts-or-volumes I think you are missing the specification of 'type' (which should be 'bind') and the target should be a directory, but you are pointing it to a file (/lib64.zip) – flagg19 Jun 27 '19 at 19:55
  • 1
    Possible duplicate of [Copying files from Docker container to host](https://stackoverflow.com/questions/22049212/copying-files-from-docker-container-to-host) – David Maze Jun 27 '19 at 21:12
  • Note: Modified answer for a tested method using volumes. – Perplexabot Jun 27 '19 at 21:29

2 Answers2

27

There are multiple ways to do this.

Using docker cp:

docker cp <container_hash>:/path/to/zip/file.zip /path/on/host/new_name.zip

Using docker volumes:

As you were leading to in your question, you can also mount a path from the container to your host. You can either do this by specifying where on the host you want the mount point to be or don't specify where the mount point is and let docker choose. Both these paths require different approaches.

Let docker choose host mount location

docker volume create random_volume_name
docker run -d --name ubuntu-libs -v random_volume_name:<path/to/mount/in/container> ubuntu-libs

The content will be located on your host, here:

ls -l /var/lib/docker/volumes/random_volume_name/_data/ 

Let me choose host mount location

docker run -d --name ubuntu-libs -v <existing/mount/point/on/host>:<path/to/mount/in/container> ubuntu-libs

This creates a clean/empty location that is shared as per the locations defined in the command. Now you need to modify your Dockerfile to copy the artifacts to this path, something like:

FROM ubuntu

RUN apt-get update && apt-get install -y build-essentials gcc

ENTRYPOINT ["zip","-r","-9"]
CMD ["sh", "-c", "/lib64.zip", "/lib64", "cp", "path/to/zip/file.zip", "<path/to/mount/in/container>"]

The content will now be located on your host, here:

ls -l <existing/mount/point/on/host>

I got to give a shout out to @joaofnfernandes from here, who does a great job explaining.

Perplexabot
  • 1,852
  • 3
  • 19
  • 22
2

As @flagg19 commented, you should be binding a directory onto a directory. You can make up directories inside the container, and you can override the RUN arguments. Doing both plus adding type=bind leads to great success:

docker run -d --rm --mount type=bind,source="$(pwd)",target=/out ubuntu-libs /out/lib64.zip /lib64

Or of course you could change the Dockerfile RUN command to write to /out/lib64.zip instead of /lib64.zip:

FROM ubuntu

RUN apt-get update && apt-get install -y build-essentials gcc && mkdir /out

ENTRYPOINT ["zip","-r","-9"]
CMD ["/out/lib64.zip", "/lib64"]
docker run -d --rm --mount type=bind,source="$(pwd)",target=/out ubuntu-libs

Either way, I recommend adding --rm and getting rid of --name. No need to keep around the container after it's done.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • I get the following error: `docker: Error response from daemon: create [PATH TO PWD]: "[PATH TO PWD]" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.` – Pardoner Jun 27 '19 at 22:57
  • hmmm, strange because the error does start with a /. `... create /Users/path/to/my/project: "/Users/path/to/my/project" ...` – Pardoner Jun 27 '19 at 23:07
  • 1
    @Pardoner add `type=bind`, right now you have no type and it defaults to `volume`, and `source` with `type=volume` wants a volume name (that's why it complains about invalid character, a path is not a valid volume name), try with: `docker run -d --rm --mount type=bind,source="$(pwd)",target=/out ubuntu-libs` – flagg19 Jun 28 '19 at 07:07