siliceum

Why I prefer painless deployments with artifact promotion

Great, your Nest.JS server that you’ve been testing on the DEV environment for a few weeks works perfectly. Just click a button to deploy it to PROD.

Except here’s the thing, you’re using code promotion and your DOCKER image in your pipeline is configured to node:latest. Last night the version was changed to v20 with all the wonderful breaking changes on the crypto dependency side.

Too bad! Yet you had tested it so thoroughly…

What a shame, you could have just used the PACKAGE that was running fine in DEV and deployed it, WITHOUT CHANGING ANYTHING.

And I don’t know about you, but on my various projects, there are always at least two main categories of environments (DEV / PROD) and this can increase depending on needs (UAT, STAGING, PRE-PROD…).

Each team having its own inertia, the delay between each step can be counted in days. So if I have to re-download my dependencies at each step, compile everything while crossing my fingers that the BUILD environment hasn’t changed, it’s opening the door to all the windows.

How I used to do it: code promotion

I pushed to a DEV branch, and off we went for INSTALL, BUILD, TESTS and DEPLOY to the DEV environment.

When we wanted to deploy to prod, a quick PR to move to a RELEASE branch (PROD for example), then off again for INSTALL, BUILD, TESTS and DEPLOY to the (PRE-)PROD environment.

In this approach, it’s the branch change policy that defines the type of artifact I create.

  • When I push to DEV, it deploys to the DEV environment.
  • When I push to PROD, it deploys to the PROD environment.

Advantages

  • Easy to understand, branch name == environment
  • Easy to version, the latest version on the branch that passes tests == the latest deployed version
  • Quick to set up for a team with multiple people

Disadvantages

  • The code may be identical, but nothing assures us that the compiled versions are. A DEV version can be different from PROD. Dependencies or the docker image that did the build may be different.
  • Longer to validate, and therefore to deploy. DEV tests will either have been skipped, or rerun for the same code (because different artifact).

And now, I prefer artifact promotion (you know, deploying the SAME thing to DEV & PROD)

I still keep a branch policy. But I decouple deployment from the act of pushing to a branch.

These are two distinct things. Pushing to a branch triggers the maximum level an artifact can reach.

  • When I push to DEV, the built artifact won’t go further than the DEV environment
  • When I tag a release version, the artifact will traverse all environments up to PROD

And how does it work?

  • Push: A version is sent to my version manager
  • Compilation & Packaging: to generate an optimal artifact, which we version. A semantic approach (Major.Minor.Patch for example) is a minimum, and with a unique build identifier it’s even better (Major.Minor.Patch.Build)! If possible, adding suffixes to differentiate DEV / PROD versions (you have the choice: SNAPSHOT, RC… This part depends on the team’s organization.)
  • Static Tests: We pass the entire static code analysis phase (quality, unit tests…) to not push what already doesn’t pass the first barrier
  • Delivery and storage: The version is delivered to a DEV artifact manager (Nexus for example)
  • Artifact audits: The CI test and audit steps retrieve the artifact and rely on it for testing.
  • DEV Deployment: We retrieve the artifact and push it to the DEV environment.

If the version is identified as “Release”, and it’s OK, we move to the next level!

  • Promotion: The DEV artifact is promoted. It moves to PROD and is “sealed”: not possible to push a version with the same number or edit its content
  • PRE-PROD environment deployment: Each PRE-PROD environment retrieves the latest artifact and passes the various tests (Migration, performance, Acceptance…)
  • Going to PROD: during the release

A critical regression bug encountered in PROD?

Just target a previous working version and launch the Rollback! (Of course, DB version management is a whole problem that we won’t address here).

The best of the best: why a different manager for DEV & PROD artifacts?

This allows better access rights management depending on teams.

We can apply different policies: for example, development artifacts can be deleted faster, while production ones must be kept longer to guarantee fast rollback.

Advantages

  • Increased reliability

With artifact promotion, we know exactly what we’re deploying. Nothing to add, everything is there. An artifact that works at each test step will work the same way in production (subject to environment differences, but this should never happen… or almost).

  • Time savings on CI & CD side

We avoid the entire BUILD & PACKAGE step + reduction of certain TESTS and DELIVER steps (artifact promotion can be done on the artifact manager side directly) which speeds up delivery cycles.

  • Ease of audit

Each artifact is versioned and accessible, which simplifies external audits.

Need to perform security, performance or accessibility benchmarks on a previous version? No problem! Everything is at hand.

Disadvantages

  • Requires a well-identified release cycle within the team
  • Implies specific tools like an artifact registry, well-designed pipelines and good flow discipline.

In conclusion

Small disclaimer at the end: I sometimes keep code promotion on still-young projects with a still-nascent release cycle. When a project is still in BUILD phase, it’s a very fast way to move forward. Especially if the company I’m at doesn’t yet have well-standardized processes in terms of RELEASE.

But, in a RUN phase where stability prevails, I have much more confidence in artifact promotion.

Photo de Cédric CHARIERE FIEDLER

Written by

Cédric CHARIERE FIEDLER

Web & API Architect – Reliability, Performance, QA

View profile