Docker for C++ build pipeline
By: Aakash Mallik
Tags: Coding, Docker Compose, Docker, Ci Cd Pipeline, Cpp

With this in mind let’s now make clear segregation between Env Image and a Dev/Prod Image.

1. Env Image

So the idea is that you would want to have an Environment Image that will be built on top of an official base Image (probably the OS and Processor architecture you are targeting). This Environment image will contain all the libraries you want to use in your project. Logically you would only update this Image when you add or remove a library from your project. Also, building libraries from source takes a huge amount of time, so you won’t want to repeat this process every time you wish to try out a new modification in your code. In our project, we use this command to build our Env Image.

docker build -t radlet/radlet_dock.env:x64 -f ./Docker/x64/env.Dockerfile .

This will take a good deal of time depending on whatever library you are trying to install/build from source.

Let’s take a look at this command and try to understand what’s going on:

-t is for tagging the image with a name — radlet/radlet_dock.env:x64 — this gives us a clear idea of what this image is. radlet/ is the name of the repo I have created on Docker Hub. This tag is used to push the image to cloud and reuse it without having to rebuild it from scratch if you don’t happen to have it locally. radlet_dock.env is the actual name and x64 is the architecture this image is expected to run on — has no functional relevance, just added it to make things clear for people using the image.

is the name of the repo I have created on Docker Hub. This tag is used to push the image to cloud and reuse it without having to rebuild it from scratch if you don’t happen to have it locally. radlet_dock.env is the actual name and x64 is the architecture this image is expected to run on — has no functional relevance, just added it to make things clear for people using the image. -f allows you to specify a docker file. We have multiple docker files in our repo in a well-structured directory, so we use this flag to point to the right docker file. Each image type in each architecture has a different DockerFile to keep things simple and clean.

Lastly, the ‘.’ that points to the root directory of the project. So I usually run this from the project root, thus ‘.’ makes sense in my case.

Now, let’s peek into the DockerFile.

Trivial stuff here but a few noteworthy points —

The base image for our env for x64 bit architecture is Ubuntu. So whatever works on Ubuntu works here.

We have a bash script to make organising library installation steps easier, so we just copy this script in the image and install the libraries using the script rather than writing the installation steps directly in the docker file.

Also, pay attention to the change of the working directory and the cleanup steps that are included in the DockerFile.

2. Dev Image

Now when we have our Environment Image ready you would use this as your base Image for the rest of your pipeline for creating Dev/Prod Images. In our project we use this command to build our Dev Image:

docker build -t radlet_dock.dev:x64 -f ./Docker/x64/dev.Dockerfile .

This is again similar to what you have done in Env. Let’s take a look at the DockerFile:

The noticeable changes are:

The base image is now radlet/radlet_dock.env:x64

We basically copy our entire source code into the Image and run CMake as usual. Assuming you know how CMake works, this should now feel like home.

To keep things even more simple for our contributors, we have packed the two commands in a bash script and fire them using flags.

In the script, you would see line number 43 and 61 doing the exact things I have mentioned above. So for a contributor to create an Env Image, he would do (while in the project root):

./package.sh -e

while to create a Dev Image, he would do something like this:

./package.sh -b

Note: This step can be used in CI/CD systems as a build test. For instance, I have used it in my project in Github Actions. So whenever we have a pull request, Github actions would initiate a ./package.sh -b command. If the build process exits with a non-zero output (you don’t really have to worry about this) then your build was successful and thus there was no syntax error. Your CI/CD pipeline can proceed further with deployment or whatever you would like it to do.