Adding a directory path to your docker image - docker

I am trying to add a directory to my docker image. I tried the below methods. During the build I dont see any errors, but once I run the container ( I am using docker-compose) and get into it docker exec -it 410e434a7304 /bin/sh I dont see the directory in the path I am copying it into nor do I see it as a volume when I do docker inspect.
Approach 1 : Classic mkdir
# Define working directory
WORKDIR /root
RUN cd /var \
mdkir www \\ no www directory created
COPY <fileDirectory> /var/www/<fileDirectory>
Approach 2 : Volume
FROM openjdk:8u171 as build
# Define working directory
WORKDIR /root
VOLUME["/var/www"]
COPY <fileDirectory> /var/www/<fileDirectory>

Your first approach is correct in principle, only that your RUN statement is faulty. Try:
RUN cd /var && mkdir www
Also, please note the fundamental difference between RUN mkdir and VOLUME: the former simply creates a directory on your container, while the latter is chiefly intended for mounting directories from your container to the host your container is running on.

This is how I made it work:
# Define working directory
WORKDIR /root
COPY <fileDirectory> /root/<fileDirectory>
RUN cd /var && mkdir www && cp -R /root/<fileDirectory> /var/www
RUN rm -rf /root/email-media
I had to copy the from my host machine to docker image's working directory /root and from /root to the desired destination. Later removed the directory from/root`
Not sure if thats the cleanest way, if I followed the approach 1 with the right syntax suggested by #Fritz it could never find the the path created and throw an error.
After running the RUN layer it would remove the container (as below) and in the COPY line it would not have the reference to the path created in the run line.
Step 16/22 : RUN cd /var && mkdir www && cp -R /root/<fileDirectory> /var/www
---> Running in a9c7df27116e
Removing intermediate container a9c7df27116e

Related

How to copy files into outside working directory

I want to copy the file to a folder location that is outside the working directory. I used the following lines in my docker file, but the files are not there when I look in the container.
WORKDIR /app
RUN cd ../opt/venv/lib/python3.7/site-packages/xxx/
COPY ./resources/abc.py .
When look a that /opt/venv/lib/python3.7/site-packages/xxx/ location the abc.py is not there
What is the issue with my approach? Appreciate your inputs.
You can't COPY a file from outside the build context. So if you are trying to COPY /opt/venv/lib/python3.7/site-packages/xxx/resources/abc.py into your docker image, and that is not in your build context, it will fail. Full stop.
Here's some annotated code.
# change to the /app directory in the container
WORKDIR /app
# run the command cd in the container. cd is a shell builtin, and after
# this command finishes you will still be inside the /app directory in
# your container.
RUN cd ../opt/venv/lib/python3.7/site-packages/xxx/
# Attempt to copy ./resources/abc.py from your host's build context
# (NOT /opt/venv/lib/python3.7/site-packages/xxx/) into the container.
COPY ./resources/abc.py .
The basic fix for this is to first copy abc.py into your build directory. Then you will be able to copy it into your docker container during your build like so:
WORKDIR /app
COPY abc.py .
# /app/abc.py now exists in your container
Note on cd
cd is a shell builtin that changes the working directory of the shell. When you execute it inside a script (or in this case a docker RUN) it only changes the working directory for that process, which ends when the script ends. After which your working directory will be the one you started in. So you cannot use it in the way you were intending. Much better explanation here.
Take this Dockerfile for example:
FROM alpine:latest
RUN cd /opt # cd to /opt
RUN pwd # check current directory, you're STILL in '/'
RUN cd /opt && \
pwd # works as expected because you're still in the same process that cd ran in.
# But once you exit this RUN command you will be back in '/'
# Use WORKDIR to set the working directory in a dockerfile
Here's the output of building that Dockerfile (removed noisy docker output):
$ docker build --no-cache .
Sending build context to Docker daemon 3.584kB
Step 1/4 : FROM alpine:latest
Step 2/4 : RUN cd /opt
Step 3/4 : RUN pwd
/
Step 4/4 : RUN cd /opt && pwd
/opt
From what I understand, you're trying to copy a file into a specific location (/opt/venv/lib/python3.7/site-packages/xxx/) in your Docker image that is outside the WORKDIR you defined in the Dockerfile for your image.
You can easily do this by specifying the absolute destination path in the COPY command:
WORKDIR /app
COPY ./resources/abc.py /opt/venv/lib/python3.7/site-packages/xxx/abc.py

Docker build "no such file or directory" error

RUN adduser -D appUser
RUN mkdir /usr/share/app
RUN mkdir /logs
ADD Function/target/foo.jar /usr/share/app
WORKDIR /usr/share/app
RUN chown -R appUser /usr/share/app
RUN chown -R appUser /logs
USER appUser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "foo.jar"]`
I've got this weird issue I can't seem to work my head around.
My root folder contains two directories, (both with subdirectories) 'Demo/Dockerfile' and 'Function/target/foo.jar'
I have a copy command in my Dockerfile that reads
COPY Function/target/foo.bar /usr/share/app
but when I run docker build -f Demo/Dockerfile from the root folder, I get an error
stat /var/lib/docker/tmp/docker-builder238823934/Function/target/foo.jar: no such file or directory
I find this a bit strange because when I edit the copy command to read COPY /target/foo.bar /usr/share/app and then I cd into the Function directory and run
docker build -f ../Demo/Dockerfile
it builds successfully, or if I edit the Dockerfile to read COPY foo.bar /usr/share/app and then cd into the target directory and run docker build -f ../../Demo/Dockerfile, this also works.
Is there an explanation for this sort of behavior?
This is what my dockerignore file looks like
!**/Dockerfile
!DockerServiceDescription/**
!Function/target/*.war
!server.xml
!tomcat-users.xml
Docker uses context directory and children only and does not allow using any files outside for security reasons.
You should show context directory to docker using '.' or so:
cd myproject
docker build -f Demo/Dockerfile .

Copying files with execute permissions in Docker Image

Seems like a basic issue but couldnt find any answers so far ..
When using ADD / COPY in Dockerfile and running the image on linux, the default file permission of the file copied in the image is 644. The onwner of this file seems to be as 'root'
However, when running the image, a non-root user starts the container and any file thus copied with 644 permission cannot execute this copied/added file and if the file is executed at ENTRYPOINT it fails to start with permission denied error.
I read in one of the posts that COPY/ADD after Docker 1.17.0+ allows chown but in my case i dont know who will be the non-root user starting so i cannot set the permission as that user.
I also saw another work around to ADD/COPY files to a different location and use RUN to copy them from the temp location to actual folder like what am doing below. But this approach doesnt work as the final image doesnt have the files in /otp/scm
#Installing Bitbucket and setting variables
WORKDIR /tmp
ADD atlassian-bitbucket-${BITBUCKET_VERSION}.tar.gz .
COPY bbconfigupdater.sh .
#Copying Entrypoint script which will get executed when container starts
WORKDIR /tmp
COPY entrypoint.sh .
RUN ls -lrth /tmp
WORKDIR /opt/scm
RUN pwd && cp /tmp/bbconfigupdater.sh /opt/scm \
&& cp /tmp/entrypoint.sh /opt/scm \
&& cp -r /tmp/atlassian-bitbucket-${BITBUCKET_VERSION} /opt/scm \
&& chgrp -R 0 /opt/ \
&& chmod -R 755 /opt/ \
&& chgrp -R 0 /scm/bitbucket \
&& chmod -R 755 /scm/bitbucket \
&& ls -lrth /opt/scm && ls -lrth /scmdata
Any help is appreciated to figure out how i can get my entrypoint script copied to the desired path with execute permissions set.
The default file permission is whatever the file permission is in your build context from where you copy the file. If you control the source, then it's best to fix the permissions there to avoid a copy-on-write operation. Otherwise, if you cannot guarantee the system building the image will have the execute bit set on the files, a chmod after the copy operation will fix the permission. E.g.
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh
A better option with newer versions of docker (and which didn't exist when this answer was first posted) is to use the --chmod flag (the permissions must be specified in octal at last check):
COPY --chmod=0755 entrypoint.sh .
You do not need to know who will run the container. The user inside the container is typically configured by the image creator (using USER) and doesn't depend on the user running the container from the docker host. When the user runs the container, they send a request to the docker API which does not track the calling user id.
The only time I've seen the host user matter is if you have a host volume and want to avoid permission issues. If that's your scenario, I often start the entrypoint as root, run a script called fix-perms to align the container uid with the host volume uid, and then run gosu to switch from root back to the container user.
A --chmod flag was added to ADD and COPY instructions in Docker CE 20.10. So you can now do.
COPY --chmod=0755 entrypoint.sh .
To be able to use it you need to enable BuildKit.
# enable buildkit for docker
DOCKER_BUILDKIT=1
# enable buildkit for docker-compose
COMPOSE_DOCKER_CLI_BUILD=1
Note: It seems to not be documented at this time, see this issue.

Dockerfile can COPY files into a declared volume, but RUN cannot create files?

I've been expiriencing a bit of weird behavior regarding volumes. We have a container which contains a database, and is expected to bind mount folders from the host which contain the data. I'm trying to create a child container which ships with test data, as it is just used for testing.
This requires that during the build step, some data is copied off the host machine, and then some scripts run which create additional files. I've noticed however though when I have a look at the running container, only the copied files exist, and the ones created by scripts do not. I've boiled down the steps to the following docker file:
FROM ubuntu:xenial-20180112.1
VOLUME /test
COPY /test/copydir/copyfile.txt /test/copydir/copyfile.txt
RUN mkdir -p /test/mkdir && \
touch /test/mkdir/touch.txt
Note that when I bash into the running container and do an
ls -l /test
I only get the 'copydir' folder. If I run an ls in my dockerfile however, I see that both folders exist.
What's going on here?
edit:
For additional context, the following prints out that both directories exist:
FROM ubuntu:xenial-20180112.1
VOLUME /test
COPY /test/copydir/copyfile.txt /test/copydir/copyfile.txt
RUN mkdir -p /test/mkdir && \
touch /test/mkdir/touch.txt && \
ls -l /test
But the following only shows that copydir exists:
FROM ubuntu:xenial-20180112.1
VOLUME /test
COPY /test/copydir/copyfile.txt /test/copydir/copyfile.txt
RUN mkdir -p /test/mkdir && \
touch /test/mkdir/touch.txt
RUN ls -l /test
I don't have the exact explanation of this but when you build an image with a Dockerfile it will make the lightest image possible. When you use RUN you don't make data persistant but you only do an action that will give a result that will not stay in the image.
Note that apt-get and yum commands make installations persist. It's kinda weird.
Try to change your Dockerfile to:
FROM ubuntu:xenial-20180112.1
RUN mkdir -p /test
COPY /test/copydir/copyfile.txt /test/copydir/copyfile.txt
RUN mkdir -p /test/mkdir && \
touch /test/mkdir/touch.txt
VOLUME /test
In a remark you said "The example I provided was cut down for clarity, in actuality the volume is defined by a parent image." That would relate the problem to the case that is not possible to undeclare a volume entry for a derived image. If that is possible (e.g. using docker-copyedit) then your problem may go away. ;)

Home symbol `~` not recognized in Dockerfile

In my dockerfile, I want to copy a file from ~/.ssh of my host machine into the container, so i worte it like this:
# create ssh folder and copy ssh keys from local into container
RUN mkdir -p /root/.ssh
COPY ~/.ssh/id_rsa /root/.ssh/
But when I run docker build -t foo to build it, it stopped with an error:
Step 2 : RUN mkdir -p /root/.ssh
---> Using cache
---> db111747d125
Step 3 : COPY ~/.ssh/id_rsa /root/.ssh/
~/.ssh/id_rsa: no such file or directory
It seems the ~ symbol is not recognized by dockerfile, how could I resolve this issue?
In Docker, it is not possible to copy files from anywhere on the system into the image, since this would be considered a security risk. COPY paths are always considered relative to the build context, which is current directory where you run the docker build command.
This is described in the documentation: https://docs.docker.com/reference/builder/#copy
As a result, the ~ has no useful meaning, since it would try and direct you to a location which is not part of the context.
If you want to put your local id_rsa file into the docker, you should put it into the context first, e.g. copy it along side the Dockerfile, and refer to it that way.

Resources