Reputation: 2186
I am investigating Docker to deploy multiple instances (here PROD-1
and PROD-2
) of multiple versions (here 1.0
) of a service. We need to configure each instance at runtime according to its instance name, and would like to bake the instance name into a Docker image as an environment variable, to avoid user error. For example:
$ cat Dockerfile
FROM ubuntu:14.04
...
$ cat Dockerfile.PROD-1
FROM docker-test:1.0
ENV DOCKER_INSTANCE PROD.1
$ cat Dockerfile.PROD-2
FROM docker-test:1.0
ENV DOCKER_INSTANCE PROD.2
$ docker build --tag=docker-test:1.0 --file=Dockerfile
$ docker build --tag=docker-test:1.0-PROD-1 --file=Dockerfile.PROD-1
$ docker build --tag=docker-test:1.0-PROD-2 --file=Dockerfile.PROD-2
I am now trying to build these images via the docker-maven-plugin
:
<plugin>
<groupId>net.wouterdanes.docker</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>build</id>
<goals>
<goal>build-images</goal>
</goals>
<configuration>
<images>
<image>
<id>base</id>
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<nameAndTag>docker-test:${project.version}</nameAndTag>
</image>
<image>
<id>instance1</id>
<dockerFile>${project.basedir}/Dockerfile.PROD-1</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-1</nameAndTag>
</image>
<image>
<id>instance2</id>
<dockerFile>${project.basedir}/Dockerfile.PROD-2</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-2</nameAndTag>
</image>
</images>
</configuration>
</execution>
</executions>
</plugin>
The problem is that I cannot configure the base image name docker-test:1.0
in Dockerfile.PROD-*
, according to the ${project.version}
Maven variable, and would instead require the developer to update the Dockerfile for each instance by hand, every time we do a release.
I got this working on the command line by writing a Ruby script to generate the Dockerfile for each instance as a heredoc, and pass it to docker build
on stdin. As far as I can see, docker-maven-plugin
does not allow me to embed a Dockerfile in the POM itself; can anyone suggest a solution?
Upvotes: 0
Views: 1438
Reputation: 7466
The latest version of the plugin lets you use build arguments, try this:
<plugin>
<groupId>net.wouterdanes.docker</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>5.0.0</version>
<executions>
<execution>
<id>build</id>
<goals>
<goal>build-images</goal>
</goals>
<configuration>
<images>
<image>
<id>base</id>
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<nameAndTag>docker-test:${project.version}</nameAndTag>
</image>
<image>
<id>instance1</id>
<dockerFile>${project.basedir}/Dockerfile.PROD-1</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-1</nameAndTag>
<buildArguments>
<version>${project.version}</version>
</buildArguments>
</image>
<image>
<id>instance2</id>
<dockerFile>${project.basedir}/Dockerfile.PROD-2</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-2</nameAndTag>
<buildArguments>
<version>${project.version}</version>
</buildArguments>
</image>
</images>
</configuration>
</execution>
</executions>
</plugin>
You can then use the build argument in your docker file to pass in the version number like so:
ARG version
FROM docker-test:$version
ENV DOCKER_INSTANCE PROD.1
ARG version
FROM docker-test:$version
ENV DOCKER_INSTANCE PROD.2
Upvotes: 1
Reputation: 2186
After some playing around, I got this working by moving the Dockerfiles for the dependent Docker images to src/main/resources/docker
:
# src/main/resources/docker/Dockerfile.PROD-1
FROM docker-test:${project.version}
ENV DOCKER_INSTANCE PROD.1
I then used Maven resource filtering to change ${project.version}
to the current version, and referenced the modified Dockerfiles in ${project.build.outputDirectory}/docker
:
# pom.xml
<build>
...
<resources>
<resource>
<directory>src/main/resources/docker</directory>
<targetPath>docker</targetPath>
<filtering>true</filtering>
</resource>
</resources>
...
<plugins>
<plugin>
<groupId>net.wouterdanes.docker</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>build</id>
<goals>
<goal>build-images</goal>
</goals>
<configuration>
<images>
<image>
<id>base</id>
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<nameAndTag>docker-test:${project.version}</nameAndTag>
</image>
<image>
<id>instance1</id>
<dockerFile>${project.build.outputDirectory}/docker/Dockerfile.PROD-1</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-1</nameAndTag>
</image>
<image>
<id>instance2</id>
<dockerFile>${project.build.outputDirectory}/docker/Dockerfile.PROD-2</dockerFile>
<nameAndTag>docker-test:${project.version}-PROD-2</nameAndTag>
</image>
</images>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
It's still not ideal, because we have to make sure the POM file matches the dependent Dockerfiles, but at least we don't have to update the version numbers by hand. If anyone has a cleaner solution (preferably requiring the instance names PROD-1
and PROD-2
to be specified only once), I would love to hear it!
Upvotes: 1