Where should I place my bash setup files when using docker? - docker

My Dockerfile is below.
Currently I copy the dotfiles (which are referenced within the .bashrc) to /root
Is there a better way to organize them?
FROM alpine:latest
LABEL maintainer="Michael Durrant<junk#snap2web.com>"
RUN apk add bash git vim
COPY alpine_bashrc /root/.bashrc
COPY .bash_functions.sh /root
COPY .bash_aliases /root
COPY .git-completion.bash /root
RUN "/bin/bash"

Instead of having 1 COPY directive for each file, it might be advisable to have a directory instead. The limitation would be that the files must be named as they would appear in the container.
$ ls .
Dockerfile
dotfiles/
.bashrc
.git-completion.bash
.bash_functions.sh
.bash_aliases.sh
Dockerfile
...
COPY dotfiles/ root/
Each of those COPY directives creates a new layer in your container. Save space/time by having one directive.

Related

How to use cp command in dockerfile

I want to decrease the number of layers used in my Dockerfile.
So I want to combine the COPY commands in a RUN cp.
dependencies
folder1
file1
file2
Dockerfile
The following below commands work which I want to combine using a single RUN cp command
COPY ./dependencies/file1 /root/.m2
COPY ./dependencies/file2 /root/.sbt/
COPY ./dependencies/folder1 /root/.ivy2/cache
This following below command says No such file or directory present error. Where could I be going wrong ?
RUN cp ./dependencies/file1 /root/.m2 && \
cp ./dependencies/file2 /root/.sbt/ && \
cp ./dependencies/folder1 /root/.ivy2/cache
You can't do that.
COPY copies from the host to the image.
RUN cp copies from a location in the image to another location in the image.
To get it all into a single COPY statement, you can create the file structure you want on the host and then use tar to make it a single file. Then when you COPY or ADD that tar file, Docker will unpack it and put the files in the correct place. But with the current structure your files have on the host, it's not possible to do in a single COPY command.
Problem
The COPY is used to copy files from your host to your container. So, when you run
COPY ./dependencies/file1 /root/.m2
COPY ./dependencies/file2 /root/.sbt/
COPY ./dependencies/folder1 /root/.ivy2/cache
Docker will look for file1, file2, and folder1 on your host.
However, when you do it with RUN, the commands are executed inside the container, and ./dependencies/file1 (and so on) does not exist in your container yet, which leads to file not found error.
In short, COPY and RUN are not interchangeable.
How to fix
If you don't want to use multiple COPY commands, you can use one COPY to copy all files from your host to your container, then use the RUN command to move them to the proper location.
To avoid copying unnecessary files, use .dockerignore. For example:
.dockerignore
./dependencies/no-need-file
./dependencies/no-need-directory/
Dockerfile
COPY ./dependencies/ /root/
RUN mv ./dependencies/file1 /root/.m2 && \
mv ./dependencies/file2 /root/.sbt/ && \
mv ./dependencies/folder1 /root/.ivy2/cache
You a re missing final slash in /root/.ivy2/cache/

What is "/app" working directory for a Dockerfile?

In the docker docs getting started tutorial part 2, it has one make a Dockerfile. It instructs to add the following lines:
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
What is /app, and why is this a necessary step?
There are two important directories when building a docker image:
the build context directory.
the WORKDIR directory.
Build context directory
It's the directory on the host machine where docker will get the files to build the image. It is passed to the docker build command as the last argument. (Instead of a PATH on the host machine it can be a URL). Simple example:
docker build -t myimage .
Here the current dir (.) is the build context dir. In this case, docker build will use Dockerfile located in that dir. All files from that dir will be visible to docker build.
The build context dir is not necessarily where the Dockerfile is located. Dockerfile location defaults to current dir and is otherwise indicated by the -f otpion. Example:
docker build -t myimage -f ./rest-adapter/docker/Dockerfile ./rest-adapter
Here build context dir is ./rest-adapter, a subdirectory of where you call docker build; the Dokerfile location is indicated by -f.
WORKDIR
It's a directory inside your container image that can be set with the WORKDIR instruction in the Dockerfile. It is optional (default is /, but base image might have set it), but considered a good practice. Subsequent instructions in the Dockerfile, such as RUN, CMD and ENTRYPOINT will operate in this dir. As for COPY and ADD, they use both...
COPY and ADD use both dirs
These two commands have <src> and <dest>.
<src> is relative to the build context directory.
<dest> is relative to the WORKDIR directory.
For example, if your Dockerfile contains...
WORKDIR /myapp
COPY . .
then the contents of your build context directory will be copied to the /myapp dir inside your docker image.
WORKDIR is a good practice because you can set a directory as the main directory, then you can work on it using COPY, ENTRYPOINT, CMD commands, because them will execute pointing to this PATH.
Docker documentation: https://docs.docker.com/engine/reference/builder/
The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction.
The WORKDIR instruction can be used multiple times in a Dockerfile. If a relative path is provided, it will be relative to the path of the previous WORKDIR instruction.
Dockerfile Example:
FROM node:alpine
WORKDIR '/app'
COPY ./package.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "start"]
A alpine node.js was created and the workdir is /app, then al files are copied them into /app
Finally npm run start command is running into /app folder inside the container.
You should exec the following command in the case you have sh or bash tty:
docker exec -it <container-id> sh
or
docker exec -it <container-id> bash
After that you can do ls command and you will can see the WORKDIR folder.
I hope it may help you
You need to declare a working directory and move your code into it, because your code has to live somewhere. Otherwise your code wouldn't be present and your app wouldn't run. Then when commands like RUN, CMD, ENTRYPOINT, COPY, and ADD are used, they are executed in the context of WORKDIR.
/app is an arbitrary choice of working directory. You could use anything you like (foo, bar, or baz), but app is nice since it's self-descriptive and commonly used.

Dockerfile COPY creates undesired subdirectory in image

I want to create a Docker container and I wrote image. Everything works great except the COPY command where I got confused. My Dockerfile:
RUN HOME=/home/ros rosdep update
RUN mkdir -p /home/ros/workspace
# Copy the files
COPY $PWD/src/a_file /home/ros/workspace/src
COPY $PWD/src/b_file /home/ros/workspace/src
a_file is a directory like a b_file. When I try to copy these directories into a newly created directory called /home/ros/workspace/src I want a_file and b_file to be both inside /home/ros/workspace/src. Instead of this, I get another src directory /home/ros/workspace/src/src) and the contents of a_file and b_file are inside that directory.
What am I doing wrong?
As mentioned in other answers, $PWDrefers to the image context.
Try to use . instead.
To setup your working directory, use WORKDIR
Also, both a_file and b_file are in src/
All in all, this should work (not tested):
FROM <your-base-image>
WORKDIR /home/ros
RUN rosdep update
RUN mkdir -p workspace
# Copy the files
COPY ./src workspace/src
In your Dockerfile, PWD variable refers to image context (i.e: inside the image).
From COPY documentation:
paths of files and directories will be interpreted as relative to the source of the context of the build.
If src directories are in the root of your build context, your example it will be:
...
COPY src/a_file /home/ros/workspace/src
COPY src/b_file /home/ros/workspace/src
...

How to specify working directory for ENTRYPOINT in Dockerfile

The Docker image (Windows-based) includes an application directory at C:\App. Inside that directory reside several sub-folders and files, including a batch file called process.bat. The Dockerfile (used to build the image) ends like this:
ENTRYPOINT [ "C:\\App\\process.bat" ]
When I instantiate this image using the command: docker run company/app, the batch file runs, but it fails at the point where other files under C:\App are referenced. Essentially, the working directory is still C:\ from the Docker container's entry-point.
Is there a way to set the working directory within the Dockerfile? Couple of alternatives do exist:
Add -w C:\App to the docker run
In the batch file, I can add a line at the beginning cd /D C:\App
But is there a way to specify the working directory in the Dockerfile?
WORKDIR /App is a command you can use in your dockerfile to change the working directory.
If /App is a mounted volume then you should specify VOLUME /App before WORKDIR to use it with ENTRYPOINT, otherwise it does not be seen by ENTRYPOINT:
VOLUME ["/App"]
WORKDIR /App
ENTRYPOINT ["sh", "start.sh"]
Which start.sh is within /App directory.

Copy specific file first and the copy all in Dockerfile

The following is what I have for my Dockerfile:
FROM node:4.6.0
WORKDIR /src
COPY node_modules/ /src/node_modules
COPY . /src/
CMD ["/bin/bash"]
I wanted to make it efficient such that node modules are copied only when there's any change in the directory. Otherwise, I want only the source files are copied into the image.
Would this work as intended?
This will copy twice. Docker cache looks at the current command and previous layer. If something has changed in the Docker context for the current command it will run. It does not use a partial cache to run.

Resources