11 Building and testing applications with Docker and Docker Compose
Docker streamlines modern application delivery by turning builds, tests, and packaging into repeatable, scriptable steps that run the same way everywhere. With Dockerfiles and Docker Compose, teams define how components are built and how services fit together, making command-line workflows ideal for automation and continuous integration. In a containerized CI pipeline, each stage runs inside containers, producing Docker images as the standard artifact, while a minimal set of shared infrastructure—source control, a registry, and an automation server—ties the process together using managed services or self-hosted options.
The chapter demonstrates how to stand up a complete build system in containers, using a lightweight Git server, a private registry, and Jenkins preconfigured to orchestrate Docker and Docker Compose. Jenkins talks to the host’s Docker Engine via the Docker API, letting it start containers for every stage of the pipeline. Build details are captured in Compose files that separate core service definitions from build-time settings, with environment variables driving image names for local and CI contexts. Dockerfiles use ARG and LABEL to record build metadata (such as build number and tag), creating an audit trail from running containers back to the exact build and source. Defaults in both Compose and Dockerfiles ensure the same definitions work locally and in CI without extra dependencies beyond Docker.
The CI job itself remains simple and portable: scripted steps invoke Docker Compose to verify prerequisites, build images (pulling fresh bases), run tests—ranging from unit checks to end-to-end flows with Compose—and push only successful images to the registry. Because stages are sequential, failed builds never publish artifacts, keeping the registry limited to viable release candidates and preserving detailed logs for traceability. The same pattern runs on any service (Jenkins, GitHub Actions, GitLab, Azure DevOps), and can be extended with production-grade safeguards like image vulnerability scanning and digital signing to enforce a secure software supply chain across all technology stacks.
The basic steps of a CI pipeline to build, test, and publish apps—all executed with Docker.
Running your whole build infrastructure in containers with one command
Running Gogs in a container. It’s an open source Git server that needs some manual setup.
Creating a new user in Gogs that you can use to push source code to the server
Creating a Git repository in Gogs where you can upload the source code for your apps
Running Jenkins in a container—it is fully configured with a user and CI job already set up.
The Jenkins job page shows the current status of the job and lets you manually start a build.
The job page in Jenkins shows the status of the most recent builds, and the pipeline steps.
Running containers with a volume to bind the private channel for the Docker API
Building images with Docker Compose and checking the image labels
Including default values for build arguments supports the developer build workflow.
Viewing the output from the pipeline build in Jenkins shows the usual Docker logs.
Sending web requests to the registry API to query the images stored in the container
A production-grade CI pipeline that adds stages with security gates
Lab
Lab time! You’re going to build your own CI pipeline—but don’t run scared. We’ll use the ideas and exercises from this chapter, but the pipeline stages will be much simpler.
In the lab folder for this chapter, you’ll find a copy of the source code for the to-do app from chapter 6. The build for that app is almost ready to go—the Jenkinsfile is there, the CI scripts are there, and the core Docker Compose file is there. There are just a couple of things for you to do:
- Write an override file called docker-compose-build.yml with the build settings.
- Create a Jenkins job to run the pipeline.
- Push your changes to Gogs in the diamol repository.
Just three tasks, but don’t be disheartened if your first few builds fail and you need to check the logs and tweak some things. No one in history has ever written a Jenkins job that passed on the first run, so here are a few hints:
- Your Compose override will be similar to the one in the exercises—specifying the context and a build argument for the build number label.
- In the Jenkins UI, you click New Item to create a job, and you can copy from the existing diamol job.
- The new job setup will be the same except for the path to the Jenkinsfile—you’ll need to specify the lab folder instead of the exercises folder.
If you’re not getting far with this, you’ll find more information in the read-me file in the lab folder, complete with screenshots for the Jenkins steps and sample build configuration for the Docker Compose file: https://github.com/sixeyed/diamol/blob/2e/ch11/lab/README.md.
Learn Docker in a Month of Lunches, Second Edition ebook for free