Personally, I find Docker extremely helpful for creating a build environment. I don't need to install tools and libraries on my local computer or on a virtual machine. I can build an environment for each library or application I want to build, I can throw it away and then recreate it every time I need.
I can have multiple versions of the same tools, but in different containers, so I don't need to worry about conflicts. I can commit my Dockerfile into some git repository, I can change computer, checkout the Dockerfile and I am ready to build. No more "it works for me" excuses :)
Pull base image
There are many images which we can use to create our build environment. We can choose among Ubuntu, Debian, Fedora, Centos, and others, which are available on Docker Hub.
Let's assume we choose Ubuntu. We can pull any version we want just passing a tag:
docker pull ubuntu:latest
docker pull ubuntu:16.04
Create Dockerfile
Let's assume we want to create our build environment using Ubuntu as operating system.
All we have to do is creating a Dockerfile, where we declare the commands required to install the tools we need, for example the GNU C compiler:
mkdir build-compiler-image
cat <<EOF >build-compiler-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get install -y gcc
EOF
Build custom image
We can create a Docker image using our Dockerfile:
docker build -t build-c build-compiler-image
Compile and execute code
We can easily compile and execute a simple C program using our custom image:
mkdir -p project/src project/bin
cat <<EOF >project/src/main.c
#include <stdio.h>
int main(int argv, char ** argc) {
printf("Hello Docker!\n");
}
EOF
docker run -it -v $(pwd)/project:/project build-c gcc -o /project/bin/main /project/src/main.c
docker run -it -v $(pwd)/project:/project build-c /project/bin/main
Cross-compile code
We can install cross compilation tools like Mingw-w64, and compile code for Windows:
mkdir build-mingw-w64-image
cat <<EOF >build-mingw-w64-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get -y install mingw-w64
EOF
docker build -t build-mingw-w64 build-mingw-w64-image
mkdir -p project/src project/bin
cat <<EOF >project/src/main.c
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MessageBox(NULL, "Hello World!", "My app", MB_OK);
}
EOF
docker run -it -v $(pwd)/project:/project build-mingw-w64 /usr/bin/i686-w64-mingw32-gcc -o /project/bin/main.exe -luser32 /project/src/main.c
Customise a library
We can compile a customised version of a library like ffmpeg:
mkdir build-autotools-image
cat <<EOF >build-autotools-image/Dockerfile
FROM ubuntu:16.04
RUN apt-get update -y && apt-get -y install git make gcc autoconf nasm yasm pkg-config
EOF
docker build -t build-autotools build-autotools-image
mkdir output
docker run -it --rm -v $(pwd)/output:/output build-autotools git clone https://github.com/FFmpeg/FFmpeg.git /output/ffmpeg
docker run -it --rm -v $(pwd)/output:/output build-autotools bash -c "cd /output/ffmpeg && ./configure --enable-gpl --disable-ffserver && make"
Execute isolated builds
One common issue with CI servers is managing multiple versions of the tools required for building code. Managing multiple versions of different tools means that we need to install and configure several plugins in our CI server and we need to configure our builds to use the correct version of those tools.
A simpler approach, which is available in Jenkins and other CI/CD solutions such as CircleCI, would be to use Docker to create the environment with the required tools for executing our builds. Using this approach we relay on Docker for creating isolated build processes which can easily run in parallel.