GCC Docker Containers
I do a lot of my development in Python, but I want to use some examples in the future of Jenkins using C++ (because it requires a compilation step). There are several versions of GCC. Rather than have multiple versions on your computer, you can use a Docker container to isolate that environment from your host’s default GCC version (see https://hub.docker.com/_/gcc/).
In addition, I want a framework that allows me to unit test my C++ code without having to install that framework on everyone else’s computer (and the build server). This will be done in a future step, but this is where we are going. So we will take one of those GCC images and add a C++ testing framework (Catch). After we have created our container, we will test it with some very simplistic C++ code.
Creating a Docker Compose File
This is not really the use case for docker-compose, but I want to present it as an interesting view. Generally docker-compose is used to start multiple services at the same time. In this case, I’m going to show multiple ‘services’ in this docker-compose file that are intended to only be different ways of running the same container. Rather than the typical “docker-compose up”, we can do “docker-compose run [service name]” in order to run one specific service from that file (and add the –rm flag to remove that container once it is done).
The ‘right’ way to use a container like this is to simply use the ‘docker run’ command with whichever options you need. I have not been a huge fan of that approach simply because one has to remember all the options needed (in this case, mapping a volume as well as the command to run – changing to a directory then running make command). Instead, I prefer the cleaner docker-compose command, generally using docker-compose up/down or docker-compose run [service name].
You can find the source code at https://github.com/tscott8706/gcc-with-catch (specifically the code within the 7/hello_world folder for this post). Rather than the normal ‘make’, ‘make clean’, and ‘./out’ (or whatever you named the executable), we can run a specific service from the docker-compose file.
1docker-compose run --rm build
1docker-compose run --rm run
1docker-compose run --rm clean
If you look within the docker-compose file, you will see there are different services for making, cleaning, and running the application. The current directory is mapped to within the container so it has access to the code to compile/run. The command goes to the mapped directory then compiles, cleans, or runs the application.
Having seen the Python unit testing image, this image is not nearly as exciting or useful. In addition, why not just run ‘make’ rather than this container? Admittedly, it does help with isolating the environment and easily swapping gcc versions (just use a different image in the docker-compose file). We will see a much bigger benefit to this in the future when we add unit testing to it. Then we don’t have to pull unit test framework code (it can already be in the container), and we may not have to add some of the boilerplate code needed for the framework. In addition… imagine if we had a docker-compose file with Jenkins, and it (somehow, I don’t know how yet) was smart enough to auto-build your code, regardless of whether it is Python or C++, based on a docker-compose file that uses a separate image for building and testing. That’s where this gets powerful. Stay tuned!