When you’re writing Dockerfiles using build arguments (which you should) it’s important to keep their scope in mind. Otherwise, you’ll get very frustrated (more than likely).
Recently, I was creating a new Dockerfile for a PHP web app that I’m building, one that I’m planning to deploy to Fly.io.
In that Dockerfile, I have the following stage:
FROM base as final
ARG DATA_DIR=/opt/data
# The PHP app lives here
WORKDIR ${APACHE_DOCUMENT_ROOT}
# Copy over the application code
COPY . .
# Copy over the Composer vendor directory from the dependencies stage
COPY --from=dependencies ${APACHE_DOCUMENT_ROOT}/vendor ${APACHE_DOCUMENT_ROOT}/
# Change the document root and enable mod_rewrite
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}/public!g' /etc/apache2/sites-available/*.conf \
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}/public!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
&& a2enmod rewrite
# Build the data directory structure and ensure that they can be written in
RUN mkdir -p ${APACHE_DOCUMENT_ROOT}/logs ${APACHE_DOCUMENT_ROOT}/cache \
&& chown -Rv ${APACHE_RUN_USER}:${APACHE_RUN_GROUP} ${APACHE_DOCUMENT_ROOT} \
&& chmod -Rv ug+w ${APACHE_DOCUMENT_ROOT}
Frustratingly, while attempting to build an image from the Dockerfile, I was getting errors relating to APACHE_DOCUMENT_ROOT
, such as the following:
=> ERROR [dependencies 6/8] RUN chown -Rv www-data:www-data ${APACHE_DOCUMENT_ROOT}
------ > [dependencies 6/8] RUN chown -Rv www-data:www-data ${APACHE_DOCUMENT_ROOT}:
0.152 chown: missing operand after 'www-data:www-data'
0.152 Try 'chown --help' for more information.
------
As you can see, the build argument was not defined, so the command using it was failing.
I was, initially, confused as I’d defined the build argument at the top of the Dockerfile, before the first stage, as follows:
ARG APACHE_DOCUMENT_ROOT=/var/www
I was of the understanding that if you define a build argument before the first stage, that it, effectively, had global scope, so was accessible to all stages within the Dockerfile.
Given that, I thought that the variable would be set at this point.
Sadly, I was wrong.
But, I always love learning and filling in the gaps in my knowledge; so this was a fun opportunity to do so.
After reviewing the Dockerfile documentation, I found the following near the end of the Scope section:
An ARG instruction goes out of scope at the end of the build stage where it was defined. To use an argument in multiple stages, each stage must include the ARG instruction.
Based on that, I defined APACHE_DOCUMENT_ROOT
in the relevant stages and removed it from the top of the Dockerfile.
On running docker build
again, the image built successfully.
It feels a bit wrong to define a build argument multiple times.
but, I can see some benefits in doing so too.
So, remember that Dockerfile build arguments go out of scope
If you’re wondering why your build arguments are not being set when building images using your Dockerfiles, more than likely, this is why.
Join the discussion
comments powered by Disqus