Skip to content

Base Containers in CI: The Key to Scalability and Security of the Entire DevOps Process

In the IT industry, there's a lot of talk about DevOps (Development & Operation), and sometimes the terms DevSecOps or DevOpsSec also appear, adding the security aspect to the entire process. And here begins a certain problem, a certain oversight, because it's assumed that these three elements are enough. Even worse, if superiors receive information (or the impression) that the prepared process will run independently for years.

In the real world, we observe three spatial dimensions and one temporal dimension. Therefore, something doesn't quite add up in the context of the first paragraph. After all, if a DevOps process is being designed, in addition to working at the present moment, it must also cope with what the future brings. This temporal dimension in DevOps processes is referred to as Maintenance. And it's just as important as the other factors, which would give us the name DevSecMntOps. So, in simple terms:

  1. A solution is designed, and application code is created.
  2. The code is analyzed to ensure high quality in terms of both programming and security.
  3. CI (Continuous Integration) processes and others should consider the need for continuous updating of external libraries as well as the base containers used in CI.
  4. Software is deployed, and feedback/monitoring is not forgotten.

How to deal with this problem? The entire CI process is best based on base containers. I believe this is a good practice because it has proven itself in real-world scenarios. Here's how it works:

Base containers are initially divided into two types:

  • Base for CI processes - Contains everything needed to run the application. Based on this, a container with the application is built, resulting in a ready, fully functional environment for testing purposes.
  • Base for client versions - Contains only the application and necessary elements, making it lightweight. The database in this case is always external.

Of course, situations vary and depend on whether the application is monolithic or consists of separate services, but the concept of base containers can be applied in all these cases.

Okay, we already have a base container, and the application has been built on it, but how do we address the Maintenance mentioned earlier? Simply parameterize the name of the base container in the CI process, which will allow easy building of the application on different base containers. When there's a need to update the base container, a new base container is built under a new name, and the CI process is tested, for example, on a new version of Linux or Node.js, GO, Python... without disrupting others' work.

If a new tag is created for each change of the base container and these images are stored, for example, in GitLab Container Registry, this also resolves the situation when a HotFix needs to be released for an older version. You take the code from the appropriate branch or tag, set the appropriate base container for that code version, and you're done.

This approach offers additional advantages, such as:

  • As you know, containers consist of layers, and once downloaded, they are not downloaded again. This means that when updating a container on a machine where the base container was downloaded, for example, on a GitLab Runner, only the application layers are downloaded.
  • The base container also protects against unexpected changes in low-level base containers, such as a Linux update within the container. Such an update can be tested beforehand before it becomes the default version for others.
  • Additionally, one of the most significant advantages: the base container is always downloaded from your own Container Registry, not from the internet.

This approach is not super lightweight, but it scales horizontally very well and, most importantly, allows for the smooth development of the system without actually having to worry about compiling legacy versions of the application as well as new versions. This solution provides the ability to inform the Dev Team in advance that the application will not compile on a new version of Linux or the programming language.

I am very curious what methods you use in your solutions. Perhaps there is another more standard or interesting approach to ensure the continuity of maintenance of CI processes and, more broadly, DevOps.