Integrating docker into a continuous integration process is a common practice with many advantages. For many companies, their first use of docker (or containers in general) is in Continuous Integration/Continuous Delivery pipelines. This approach has many of the standard container advantages, including these highlights:
- Consistent, immutable build environments: After spinning up, a docker container will always be exactly the same. This allows build environments to be consistent and in a known-state. There is no question as to whether you remembered to install the build tool on the new build server. As long as it is in the dockerfile, it’s in the container.
- Lightweight: Docker containers should be designed to be small and only contain exactly the tools they need. This, combined with how layers work in docker, allows them to be built and discarded quickly.
- Ephemeral: Docker containers in a build process are designed to only be around for as long as it takes them to do a job. They are not long-standing servers that need to be maintained, patched, updated, etc. This lifecycle means less overhead and more flexibility for a team that would typically be forced to maintain a fleet of servers. If a patch needs to go out, you update the dockerfile and publish a new version of the docker image.
However, to realize these benefits you need to properly manage your dockerfiles and docker images. If you only have one dockerfile and image to manage and version, you might be able to get away with the building and publishing them manually. However, very few companies have just one dockerfile and image to manage (in fact if they do, I’d question why they were bothering with docker in the first place). To help with the management of these images, I’ve collected some common approaches.
This by no means a comprehensive list of approaches to managing docker and there is no one, true way either. Think of this list as more of a list of ideas to consider. Every company and situation is different and most likely these ideas will fit into a strategy not be the strategy.
- One repo with all “build” images
- CI will only build and publish images that have changed.
- Use git, or other source control management tool to generate a list of changed files. Filter based on dockerfiles or other criteria.
- Organize dockerfiles into directories, based on teams, projects, etc.
- Very freeform.
- Lets you create a new CI/CD process without having to worry about retrofitting into existing pipelines.
- Access to repo can be limited to those who need it. Can be restricted to a “DevOps” team or whoever should maintain these images.
- Centralized repo and process that is easy to point to and maintain. Keeps process consistent with many examples to reference.
- Prevents repo sprawl where you end up with many different tiny repos to manage access to.
- Consistent CI/CD process. If updating the CI/CD process for building docker agents, only need to update one CD/CD, instead of potentially dozens.
- Cannot limit access to folders, so if one has access to the repo, they have access to every dockerfile within repo.
- Another repo and CI/CD process to maintain separate from app repositories.
- Potentially separates Application developers from the build environments, encouraging Silos.
- Consistency across CI/CD comes at the cost of more customized Continuous Integration processes for different needs.
Dockerfiles for build environments in their respective repos.
- CI in each Repo to build/publish Docker images.
- Simpler, granular access. Anyone who has access to the application repo has access to any dockerfiles for their build environments.
- Brings Devs closer to the build environments, reducing silos.
- Allows greater customization of CI processes for each repository.
- Have to retrofit a docker build step into existing, potentially very complex CI/CD process.
- No general CI/CD process across different projects.
- If one wants to add something to every docker process (such as a container security scanner for instance), one need to add it to dozens of different repos and files.
- Near impossible to account for and manage every dockerfile and associated docker build process.
Separate Repo for every built environment, split from the app repo. A repo for every Docker image with its own CI/CD pipeline.
- Highly custom Continuous Integration pipeline for each docker image.
- The model can leverage inheritance very well. Where one docker image can be built upon another. Other models can take advantage of this as well, but this model lends itself well to it.
- Major repo sprawl.
- No general process for building/publishing docker images.
- Have to update several CI/CD pipelines.
- Developers have approved base images that they are allowed to build their build images off of.
- Ability to vet/harden certain aspects of docker images before reaching developers.
- A centralized “core”. Process is consistent for the base images, and updating generalized process is possible at base level.
- Can slow developers down. Often base images are available online that are ready for certain tasks. With a base image, they would need to setup and configure these themselves.
- Adds potential for red tape. If a base image is inadequate for the job that needs to be done then they will need to have a new base image vetted and approved.
- No control to what developers do on top of the base image in their dockerfiles.