How to retrieve file from docker container? - docker

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.

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.

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.

Related

I try to build a docker container that include externals files

I try to create a docker container with bind9 on it and I want to add my db.personal-domain.com file but when I run docker build and then docker run -tdp 53:53 -v config:/etc/bind <image id> the container doesn't have my db.personal-domain.com file. How to fix that ? Thanks !
tree structure
-DNS
--Dockerfile
--config
---db.personal-domain.com
Dockerfile
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y bind9
RUN apt-get install -y bind9utils
WORKDIR /etc/bind
VOLUME ["/etc/bind"]
COPY config/db.personal-domain.com /etc/bind/db.personal-domain.com
EXPOSE 53/tcp
CMD ["/usr/sbin/named", "-g", "-c", "/etc/bind/named.conf", "-u", "bind"]
There is a syntax issue in your docker run -v option. If you use docker run -v name:/container/path (even if name matches a local file or directory) it mounts a named volume over your configuration directory. You want the host content, and you need -v /absolute/host/path:/container/path syntax (the host path must start with /). So (on Linux/MacOS):
docker run -d -p 53:53 \
-v "$PWD:config:/etc/bind" \
my/bind-image
In your image you're trying to COPY in the config file. This could work also; but it's being hidden by the volume mount, and also rendered ineffective by the VOLUME statement. (The most obvious effect of VOLUME is to prevent subsequent changes to the named directory; it's not required to mount a volume later.)
If you delete the VOLUME line from the Dockerfile, it should also work to run the container without the -v option at all. (But if you'll have different DNS configuration on different setups, this probably isn't what you want.)
-v config:/etc/bind
That syntax creates a named volume, called config. It looks like you wanted a host volume pointing to a path in your current directory, and for that you need to include a fully qualified path with the leading slash, e.g. using $(pwd) to generate the path:
-v "$(pwd)/config:/etc/bind"

See image generated in docker

I created a Docker like:
FROM rikorose/gcc-cmake
RUN git clone https://github.com/hect1995/UBIMET_Challenge.git
WORKDIR /UBIMET_Challenge
RUN mkdir build
WORKDIR build
#RUN apt-get update && apt-get -y install cmake=3.13.1-1ubuntu3 protobuf-compiler
RUN cmake ..
RUN make
Afterwards I do:
docker build --tag trial .
docker run -t -i trial /bin/bash
Then I run an executable that saves a .png file inside the container.
How can I visualize the image?
You can execute something inside the container.
To see all containers you can run docker ps --all.
To execute something inside container you can run docker exec <container id> command.
Otherwise you can copy files from container to host, with docker cp <container id>:/file-path ~/target/file-path
Please mount a localhost volume(directory) with container volume(directory) in where you are saving your images.
now all of your images saved in container directory will be available in host or localhost mount directory. From there you can visualize or download to another machine.
Please follow this
docker run --rm -d -v host_volume_or-directory:container_volume_direcotory trial
docker exec -it container_name /bin/bash

run docker container as a arbitrary user passed to it while running the image

I want to run a docker container as an arbitrary user which is passed to the image while running it. For example docker run -u 1000 myimage.
The above is possible. However I want to create a home directory with this user 1000 while starting the container(possibly through CMD) and do my container service stuff within that directory.
Is this possible and some pointers would be useful on ways to achieve it.
First save your current user and group in variables:
export uid=$(id -u)
export gid=$(id -g)
Then to run your image,you have two options:
1) Run the image from the location of the app directory itself:
sudo docker run -d \
--user $uid:$gid \
-v $(pwd):/home/$USER \
--workdir="/home/$USER" \
myimage
2) Create a new directory for the app, e.g. at /home/$USER/app, but then you will have to write in command line your CMD from the docker file.
For example if this was your Dockerfile:
FROM node:7
WORKDIR /app
COPY package.json /app
COPY . /app
CMD node bin/www
Your would run it like that:
sudo docker run -d \
--user $uid:$gid \
-v $(pwd):/home/$USER \
--workdir="/home/$USER" \
hello-express \
bash -c "cp -rf /app/* /home/$USER/; node bin/www"
Here you pass the user to the container using $uid:$gid and you mount the user's home directory as a volume and then set it as the working directory.
I know it's quite complex, but it's the only way to achieve exactly what you want.
If you want a simpler solution, consider planning it differently. See this example for running a docker container as a non-root user.

How can I access the /etc of a pulled servicemix image

I need to install a custom bundle in a dockerized servicemix image. To do so, I need to paste some files in the /etc directory of the servicemix image.
Could anyone help me doing this?
I've tried using the Dockerfile as follows:
But it simply doesn't work. I've looked through the documentation of the image, and the author tells me to use the command: docker run --volumes-from servicemix-data -it ubuntu bash and inspect the /servicemix, but it's empty.
Dockerfile:
FROM dskow/apache-servicemix
WORKDIR .
COPY ./docs /apache-servicemix/etc
...
Command suggested by the author:
docker run --volumes-from servicemix-data -it ubuntu bash
I was unfamiliar with this approach but, having looked at the source (link), I think this is what you want to do:
Create a container called servicemix-data that will become your volume:
docker run --name servicemix-data -v /servicemix busybox
Confirm this worked:
docker container ls --format="{{.ID}}\t{{.Names}}" --all
42b3bc4dbedf servicemix-data
...
Then you want to copy the files into this container:
docker cp ./docs servicemix-data:/etc
Finally, run servicemix using this container (with your files) as the source for its data:
docker run \
--detach \
--name=servicemix \
--volumes-from=servicemix-data \
dskow/apache-servicemix
HTH!
Changes in the container will be lost until it is committed back to the image.
You can use this docker file https://hub.docker.com/r/mkroli/servicemix/dockerfile and your copy statement just before the ENTRYPOINT.
COPY ./docs /opt/apache-servicemix/etc

How to specify in Dockerfile that the image is interactive?

I have created a docker container that runs a command line tool. The container is supposed to be interactive. Am I somehow able to specify in the Dockerfile that the container is always started in interactive mode?
For reference this is the dockerfile:
FROM ubuntu:latest
RUN apt-get update && apt-get -y install curl
RUN mkdir adr-tools && \
cd adr-tools && \
curl -L https://github.com/npryce/adr-tools/archive/2.2.0.tar.gz --output adr-tools.tar.gz && \
tar -xvzf adr-tools.tar.gz && \
cp */src/* /usr/bin && \
rm -rf adr-tools
CMD ["/bin/bash"]
EDIT:
I know of the -it options for the run command. I'm explicitly asking for a way to do this in the docker file.
EDIT2:
This is not a duplicate of Interactive command in Dockerfile since my question addresses an issue with how arguments specified to docker run can be avoided in favor of specifying them in the Dockerfile whereas the supposed duplicate addresses an issue of interactive input during the build of the image by docker itself.
Many of the docker run options can only be specified at the command line or via higher-level wrappers (shell scripts, Docker Compose, Kubernetes, &c.). Along with port mappings and network settings, the “interactive” and “tty” options can only be set at run time, and you can’t force these in the Dockerfile.
You can use the docker run command.
docker build -t curly .
docker run -it curly curl https://stackoverflow.com
The convention is:
docker run -it IMAGE_NAME [COMMAND] [ARG...]
Where [COMMAND] is curl and [ARG...] are the curl arguments, which is https://stackoverflow.com in my example.
-i enables interactive process mode. You can't specify this in the Dockerfile.
-t allocates a pseudo-TTY for the container.
Are you looking for the -it option?
From the Docker documentation:
For interactive processes (like a shell), you must use -i -t together
in order to allocate a tty for the container process.
So, for example you can run it like:
docker run -it IMAGE_NAME [COMMAND] [ARG...]
Actually, in Ubuntu, I am running Apache Server in the background.
But for you, Try with below command and you should be able to go inside docker container.
docker exec -i -t your_container_name bash

Resources