Sometimes when building Docker images, if we have custom files or resources we want to use and multiple images are going to use them, it is interesting to have then just once in a shared folder and to have all Dockerfile commands pointing to that shared folder.
The problem with this is that, when we are running a build, docker use as a context the current directory where the docker build command runs and, this, initially, can cause some fails.
Let’s see an example of this. Let’s imagine we have a few projects with a structure like this:
projectA -> DockerfileA -> fileA -> resources -> script.sh -> resources -> certs -> cert projectB -> DockerfileA -> fileB -> resources -> script.sh -> resources -> certs -> cert projectC -> DockerfileA -> fileC -> resources -> script.sh -> resources -> certs -> cert
In the above folder structure, we have three different projects and we can see we have some duplicated resources making more difficult to maintain and been error-prone. For this reason, we decide to restructure the folders and shared resources in something like:
projects -> projectA -> DockerfileA -> projectA -> fileA -> projectB -> DockerfileB -> projectB -> fileB -> projectC -> DockerfileC -> projectC -> fileC -> resources -> script.sh -> resources -> certs -> cert
As we can see, the above structure seems easier to maintain and less error-prone. The only consideration we need to have now is the docker build context.
Let’s say our Dockerfile files, among others, has the ADD or COPY commands inside. In this case, something like:
...
COPY ./resources/script.sh /opt/
COPY ./resources/certs/cert /opt/cert
...
Building docker images under the first folder structure is something like:
(pwd -> ~/projectA) $ docker build -t projectA . (pwd -> ~/projectB) $ docker build -t projectB . (pwd -> ~/projectC) $ docker build -t projectC .
But, if we try to do it in the same way using the second folder structure we are going to be prompted with an error:
COPY failed: Forbidden path outside the build context.
This is because the context when executing the docker command does not have access to the folders allocated in the parent folder.
To avoid this problem, the only thing we need to do is to execute the build command from the parent folder and to add an extra flag (-f) to our command to point to the Dockerfile file we want to use when building the image. Something like:
(pwd -> projects) $ docker build -t projectA -f projectA/DockerfileA . $ docker build -t projectB -f projectB/DockerfileB . $ docker build -t projectC -f projectC/DockerfileC .
This should solve the problem as now, the context of the docker build command is the parent folder.