Docker as a Build Environment

In this post, I have tried to explain how Docker can be used as build environment for compiling and delivering various kind of applications.

Some advantages of using building applications using Docker

  • No need to have a physical build machines.
  • No need to install SDKs, Build Tools, Cross Compilers and other dependencies.
  • Developers can have same build environment on their local machines as the one used for production.
  • Docker images targeting standard build environments like Maven, NPM, GCC already available on Docker Hub.
  • Docker images can be easily created for specific requirements (like a specific compiler version, some specific cross compiler) and upload to a Public or Private Docker Repository. These can then be used for building the application.

Build a JAVA application using Maven
docker volume create --name maven-repo

docker run --rm -v “$PWD”:/usr/src/docker-build -v maven-repo:/root/.m2 -w /usr/src/docker-build maven:3.6.3-jdk-11 mvn clean package

Explanation of command:

  • Create a docker volume named maven-repo . This is done so that we can reuse the maven dependencies that get downloaded as part of a maven build.
  • Next we create a container using the image maven:3.6.3-jdk-11
  • Current directory from host machine is mounted inside the container at /usr/src/docker-build using -v option so that application sources are available in side the container.
  • Docker volume maven-repo is mounted inside the container at /root/.m2 using -v option so that Maven repository can be reused in subsequent builds.
  • Container working directory is set as /usr/src/docker-build using -w option where we are expecting the sources and POM file.
  • The container will execute the commands mvn clean package .
  • Once compilation is successful, maven creates a target folder in the next to the POM file where the build artifacts are located. Since we mounted the current directory on the host inside the container, the target folder is available on the host even when the container exits. Thus we can easily access the target folder after the build is completed.
  • The container is to be removed automatically after its execution is complete. This is done by specifying the -rm option.

Docker - Compile Maven Application as Image

FROM maven:3.6.3-jdk-11
WORKDIR /usr/docker-build
COPY pom.xml .
RUN mvn dependency:resolve dependency:resolve-plugins
ADD src ./
RUN mvn package

Explanation of Dockerfile:

  • Build and image using maven:3.6.3-jdk-11
  • Set the working directory as /usr/docker-build
  • Copy the POM file into container working directory.
  • Resolve Maven dependencies. We are doing this separately so that once Maven dependencies get resolved, they are not done again in subsequent builds unless there is a change in the POM file. We are utilizing the Docker image caching concept here.
  • Copy sources into container working directory.
  • Run maven command to compile the project.

Build a C application using gcc
docker run --rm -v “$PWD”:/usr/src/docker-build -w /usr/src/docker-build gcc:4.9 gcc -o helloworld helloworld.c

Build a C application on Linux for Windows using Cross Compiler
Dockerfile to create the Image for Cross Compiler

FROM ubuntu:16.04
RUN apt-get update -y && apt-get -y install mingw-w64
CMD [“bash”]

Build the image using the command
docker image build -t “c-cross-compile” .

Compile the application using the command
docker run --rm -v “$PWD”:/usr/src/docker-build -w /usr/src/docker-build c-cross-compile:latest /usr/bin/i686-w64-mingw32-gcc -o helloworld.exe -luser32 helloworld.c

Build a .NET application using Visual Studio Build Tools
Dockerfile to create Visual Studio Build Tools Docker Image can be found here
https://docs.microsoft.com/en-us/visualstudio/install/build-tools-container?view=vs-2019

Create a Docker image for Visual Studio Build Tools 2019 using above Dockerfile
docker image build -t “buildtools-vs-2019” .

Compile a Visual Studio Solution
docker run --rm -v C:\Users\Administrator\Desktop\Docker_DOTNET\HelloWorldDOTNET:C:\docker-build -w C:\docker-build buildtools-vs-2019:latest “nuget restore HelloWorldDOTNET.sln; msbuild HelloWorldDOTNET.sln /t:Clean,Build /P:Configuration=Release”

Multi Stage Dockerfiles

  • Combine various build steps into a single Dockerfile.
  • Each step can be defined as an individual stage with an alias to reference it.
  • Output from one stage can be used in following stages.
  • Final image can just have the built artifacts.

Multi Stage Dockerfile
FROM openjdk:11-jdk as build
WORKDIR /usr/docker-build
COPY *.java .
RUN javac HelloWorld.java

FROM openjdk:11-jre-slim-buster
WORKDIR /usr/my-java-app
COPY --from=build /usr/docker-build/HelloWorld.class /usr/my-java-app/HelloWorld.class

ENTRYPOINT [“java /usr/my-java-app/HelloWorld”]

Cloud Native Solution - GCP Google Cloud Build
Cloud Native build services like Google Cloud Build also use the concept of building applications using Docker. The example given below describes a Google Cloud Build configuration file where its is seen that a Maven image from Google’s container repository (also referred to as Cloud Builder Images) is used to compile a Maven project.

Cloud Build Config File
{
“steps”: [
{
“name”: “gcr.io/cloud-builders/mvn”,
“args”: [
“package”
]
}
],
“artifacts”: {
“objects”: {
“location”: “gs://maven-artifacts”,
“paths”: [
“target/*.jar”
]
}
}
}

// The source code, POM file and build-config.json are expected to be in the current directory
gcloud builds submit --config build-config.json
gsutil cp gs://maven-artifacts/mavendemo-0.0.1-SNAPSHOT.jar .