Conditional evaluation in Docker files

In general, a Docker build file (Dockerfile) should be usable on any Docker server. In some cases however, you would like to have something like a conditional ‘IF’ statement in your Dockerfile. To give an example: It is common usage to use apk/apt-get/curl or any other tool in your build that needs to download data from the Internet.
Alas, in some networks the use of a HTTP(S) proxy is mandatory and thus an impediment.

In this article we will show how to run a proxy-agnostic Docker build. The described mechanism is also usable for other circumstances.

Problem

When the build runs in a network environment with a HTTP proxy we need to configure the environment variable “http_proxy“. This variable is a standard way to declare the use of a HTTP proxy and will be evaluated by tools like wget or curl.

FROM any/thing
...
ENV http_proxy=http://proxy.mycompany.com:1234
...

The value might as well be passed as a “build argument” or with ” -e”, instead of hard-coding it. However, what will be the value for the environment variable in a non-proxy setting? An empty string will not help since most tools check for the mere existence of the variable.

You could set the variable in every RUN statement using the shell language to check the conditions. However this is cumbersome and ugly.
Putting the variable in a .profile or the like and copy that file to the container does not work, unfortunately, because RUN statements will ignore it (they execute /bin/sh -c).

Solution

The solution we came up with is to put a placeholder into the Dockerfile:

FROM any/thing
...
# Template
${VAR_HTTP_PROXY}
...

Yet how and when is this template being filled?

We are commonly using Maven as our build tool, so the trick is to let Maven do the job using resource filtering. We first define a default value for the substituted variable that is valid but has no effect (a comment):

<properties>
    <VAR_HTTP_PROXY>#</VAR_HTTP_PROXY>
</properties>

Second, we define a profile that will override the default value if a given environment variable “HTTP_PROXY” (or anything else that fits your needs) exists in the calling process:

<profiles>
    <profile>
        <id>with-proxy</id>
        <activation>
            <property>
                <name>env.HTTP_PROXY</name>
            </property>
        </activation>

        <properties>
            <VAR_HTTP_PROXY>ENV http_proxy=http://proxy.mycompany.com:1234</VAR_HTTP_PROXY>
        </properties>
    </profile>
</profiles>

Lastly, you need to configure the resource and Docker plugins:

...
    <resources>
        <resource>
            <directory>src/main/docker</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
...
  <plugin>
    <groupId>com.spotify</groupId>
    <artifactId>dockerfile-maven-plugin</artifactId>

    <executions>
        <execution>
            <id>build</id>
            <phase>compile</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
    </executions>

    <configuration>
        <contextDirectory>${project.build.outputDirectory}</contextDirectory>
    </configuration>
</plugin>

Caveat and conclusion

Be aware that the environment variables set in the docker file persist in the running container. I.e. the running process will see an environment variable named “http_proxy” with the specified value. This may not always be what you want.

The solution we described here may be also be used under other circumstances where you need to influence the build process conditionally. The placeholder may be filled with any directive and the Maven profile may be activated by any other condition you define.