Docker is by far the most popular software for containerization of applications. Containers make it easy to package, release, deploy and execute an application stack in a consistent and repeatable manner. However, there is more to Docker than packaging and orchestrating an application stack. Docker can also be used to build code, execute scripts and execute steps in a CI/CD pipeline. You can also use docker to try out tools without needing to install them on your machine.
Executing CI/CD Steps Within Containers
There are many build tools, such as Jenkins, Bitbucket and GitLab that support running steps of a pipeline within a running docker container. This has the following advantages:
- Build dependencies like node, maven, java, etc are no longer needed to be installed on the build server
- Application teams can dictate and maintain their build dependencies
- Developers can build code exactly the same way the build server does
Typically each step in a pipeline can define what image to run as a container. Here is an example of a GitLab pipeline YAML for a build step that uses maven:
image: maven:latest
stages:
- build
build:
stage: build
script:
- mvn package
Executing Build Steps Locally
The same build steps that run during the CI/CD pipeline can also be ran locally. This can be done via docker by running a container and volume mapping the source location. A few examples are:
docker run --rm -v $(PWD):/usr/src/app -w /usr/src/app node:4 npm install
docker run --rm -v $(PWD):/usr/src/app -w /usr/src/app maven:3.5.3 mvn clean install
docker run --rm -v $(PWD):/usr/src/app -w /usr/src/app gradle:4.7 gradle clean build
Executing Scripts
Docker can also be used to execute other things that are needed for a release such as scripts or data migration utilities. These changes can be packaged as a Docker image that is versioned along with the release they are needed for. This allows the installation of a release to be repeatable and testable via automation. Packaging and executing these tasks via Docker provides the ability to virtually remove the need for an installation playbook because those steps are authored within a Docker image. If scripts are packaged in an image named "migration-utils" you can run them and even pass parameters to them. For example, if you want to execute a script named "runFileMigration.sh prod" in your "migration-utils" image you would execute the following:
docker run --rm -v local-dir:/path/to/files --entrypoint=runFileMigration.sh migration-utils prod
Notice how when you override the entrypoint the argument "prod" is now sent as the argument to the defined entrypoint. In this example you specify a volume that represents where the files are that the script needs access to.
Experimenting With Tools
I recently attended a webinar that walked through a demo of a tool that executes static analysis of kubernetes manifests. The tool seemed quite interesting and they provided a link to the project location on github. Within the README it had various installation instructions for installing the tool. There were options for Windows, Linux, Mac (Home Brew) and a docker image. I immediately copy/pasted the instructions for the docker run
command and changed a few things for my particular file location. I then went looking for similar tools to compare and contrast the output and see if I liked the functionality of one over the other. In each case if they provide a docker image I just run that. This provides two advantages. The first is that I don't have to install each of these tools on my machine and then uninstall them if I don't like them. The other is that if I execute things via the docker run
command and I get the various parameters and settings the way I like them I can easily convert that command to a corresponding declaration in a CI file.
Conclusion
There are many more examples of using Docker for things other than building images and running containerized applications. Weather it be for CI/CD, executing scripts or experimenting with tools or anything else you can think of, feel free to try using a docker image the next time you want to install and/or get something working.