DevOps is a set of practices, tools and habits that brings together the people who build software (Dev) and the people who run it in production (Ops). The goal is easy to state: get a change from a developer’s laptop to users quickly, repeatably and safely.
For decision-makers, the list of tools matters less than the path. Every change, whether a new feature or a bug fix, always follows the same route, checked by machines wherever possible and by people where it counts. Once that route exists, releasing software stops being an event and becomes routine.
Here we follow it step by step, with the most widely used tools and a few examples from our projects.

Version control: branches and pull requests
It all starts with Git, the version control system. Each change begins on a branch, a separate line of work, and goes back into the main branch through a pull request (a merge request in GitLab): a request to integrate the change that a colleague reviews before approving it. The main branch is protected, nobody writes to it directly, and changes stay small, so the review is real rather than a formality.
This rhythm fits well with sprints, which we describe in our article on Agile Scrum: each story turns into one or more small changes, reviewed and integrated early.
Continuous integration: the automated checks
CI (continuous integration) is a pipeline, a sequence of automated steps, that runs on every proposed change:
- Build: compile the project and resolve its dependencies.
- Tests: unit and integration tests and, where needed, end-to-end tests on the user interface.
- Quality: linters and static analysis, for example with SonarQube, with thresholds that block the merge.
- Security: scanning the code (for example with Semgrep), libraries with known vulnerabilities and any secrets committed to the repository by mistake.
If a step fails, the change does not get in. The most common tools are GitHub Actions, GitLab CI/CD and Jenkins; in all of them the pipeline is defined in a file that lives in the repository alongside the code, so it is versioned and reviewed like everything else.
Containers: the same package everywhere
Once the checks pass, the pipeline builds a container image: a package, usually built with Docker, holding the application and everything it needs to run. The image is built only once, tagged with its version and stored in a registry; then the very same image moves from testing to production. That is the end of the classic “it works on my machine”.
Containers are not just for the cloud: in the ERP for Atac’s tenders, built for Ernst & Young, each microservice runs in a Docker container on the client’s on-premise system.
Automated release to each environment
Continuous delivery takes the image into each environment, typically development, staging and production, through the same automated process. Where there are many services that need to scale, Kubernetes is a common choice: it spreads containers across servers, restarts them when they fail and rolls out new versions gradually. In other cases a cloud provider’s managed services or a single server running Docker are enough. The project decides, not habit.
Two examples from our work. In 2VitaBCognitive for Atlantia, the 6 microservices are released through AWS CodeCommit, CodePipeline and CodeDeploy and run in Docker containers on Amazon ECS. In ATS, our recruiting system, GitHub Actions ships the code to Docker on the server, behind Caddy, with backup and automatic rollback.
Infrastructure as code
Servers, networks and databases are described in versioned files too. Terraform (or its open source fork OpenTofu) declares the cloud resources, and Ansible configures the servers. The benefit is concrete: environments can be recreated identically, infrastructure changes go through review just like code, and after a failure you rebuild from a known description rather than from someone’s memory.
Monitoring, alerts and rollback
The work does not end with the release. Prometheus collects metrics (response times, errors, resource usage), Grafana turns them into dashboards, and alerts notify the team when a threshold is crossed, ideally before users notice. Centralised logs then help work out what happened.
When a release goes wrong you need a rollback, a return to the previous version. With versioned images you simply put the previous one back into service; the tricky part is data, so database changes should be designed to stay compatible with the previous version for at least one release.
The part you cannot automate
DevOps is above all a way of working:
- Small, frequent releases: a small change is easier to review, easier to test and, if needed, quick to undo.
- Shared responsibility: developers also follow how their code behaves in production, and the people who run the infrastructure take part in design decisions.
- Blameless reviews: after an incident, the team looks for the cause in the process, not for someone to blame, and adds a check so it does not happen again.
- Shared measures: the DORA research programme (DevOps Research and Assessment) made indicators such as deployment frequency, lead time from change to production, change failure rate and time to restore service widely used.
If you want to build or review the path that takes your code to production, or add a team that already works this way alongside yours, let’s talk.



