Skip to main content
Dec 2021 - Oct 2022CI/CD & Platform Migration

Jenkins to GitLab Migration

You know what really gets me about infrastructure work? It's when you inherit a system that's literally falling apart at the seams. That's exactly what happened at this UK-based company with over one million active users...

The System That Was Falling Apart

You know what really gets me about infrastructure work? It's when you inherit a system that's literally falling apart at the seams. That's exactly what happened at this UK-based company with over one million active users. Their Jenkins setup wasn't just problematic - it was becoming an existential threat to their ability to ship software.

Picture this - developers would push code, trigger a build, and then... nothing. The Jenkins master would hit 100% CPU and just freeze. Not slow down, not struggle - completely freeze. Teams would be sitting there, waiting to deploy critical fixes, and our entire CI/CD pipeline would be having a meltdown.

And the plugin conflicts? Oh man, don't get me started. We'd have one team install a plugin they needed, and it would break three other teams' builds. Every week brought a new compatibility nightmare. What should have been our deployment enabler was becoming the biggest bottleneck in the entire organization.

Failing Jenkins System
Migration Strategy

The Migration Nobody Wanted But Everyone Needed

Our head of DevOps finally said what everyone was thinking - "We're moving to GitLab." But here's the thing about migrations at this scale: you can't just flip a switch. We had over a million users depending on our services. One botched deployment could affect real people trying to use our platform.

I spent over a year on this migration. A full year. And you know what? We needed every single day of it. Because this wasn't just about moving from one tool to another - it was about fundamentally rethinking how we did deployments while keeping everything running.

The approach we took was what I call "surgical precision." We ran both systems in parallel. Jenkins kept running (and breaking, and getting fixed, and breaking again) while we slowly, carefully moved workloads to GitLab. It was like performing engine maintenance while driving down the highway.

Starting Small, Learning Big

I started with the safest, smallest jobs I could find. Sync operations, internal tooling, the stuff that if it broke, wouldn't page anyone at 3 AM. These became my playground for understanding GitLab's pipeline syntax.

And let me tell you, the learning curve was real. Jenkins and GitLab think about CI/CD in fundamentally different ways. In Jenkins, everything is a job with steps. In GitLab, everything is a pipeline with stages. Sounds similar, right? Wrong. It's like the difference between driving a car and flying a plane - same goal, completely different approach.

Every small job I migrated taught me something new. How GitLab handles artifacts differently. How environment variables work. How to structure pipelines for reusability. These early migrations were my education, and they prepared me for the real challenges ahead.

Learning Process
Template Complexity

The Template Challenge That Nearly Broke Me

Here's where things got really interesting. We had hundreds of repositories that would eventually need migration. Writing individual pipelines for each one wasn't just impractical - it was impossible. We needed templates.

But creating GitLab pipeline templates that could serve hundreds of different projects? That's like designing a key that needs to open hundreds of different locks. Every template had to be flexible enough to handle different languages, different deployment targets, different testing requirements, but still maintain consistency.

The versioning complexity nearly drove me crazy. When you update a template that 200 repositories depend on, you better be sure it's backward compatible. One breaking change and you've just stopped deployments for half the company. I learned to treat template updates like API changes - semantic versioning, deprecation notices, migration guides, the whole nine yards.

The Serverless Revolution That Changed Everything

But here's what really blew my mind about GitLab - the infrastructure approach. Our Jenkins setup had dedicated slaves that sat there, burning money whether they were building or not. We had to maintain them, patch them, worry about capacity.

GitLab? Completely different game. It spun up ECS containers on-demand for each pipeline execution. When no pipelines were running, we had zero infrastructure cost for CI/CD compute. Zero. Let that sink in.

We had this entire cluster dedicated to running pipelines, but it operated on serverless principles. Need to run 50 builds simultaneously? No problem, containers spin up automatically. Nobody deploying at 2 AM? No containers, no cost. It was like having an infinitely scalable build farm that only existed when you needed it.

Serverless Revolution
Parallel Validation

The Parallel Pipeline Validation That Saved Our Bacon

Now, here's where I got really clever (if I do say so myself). The biggest fear in any migration is "what if the new system doesn't produce the same results?" So I built a validation system that would make NASA proud.

For critical services, I set up parallel pipelines. The same commit would trigger both Jenkins and GitLab pipelines. Then - and this is the clever bit - I used commit hash comparison to verify both systems produced identical artifacts.

We'd run both pipelines, compare the Docker images they produced, verify the tags matched, ensure all artifacts were identical. Only when we had weeks of data showing perfect parity would we cut over completely. It was like having a safety net under our safety net.

Managing the Human Side of Change

You know what the hardest part of this entire migration was? It wasn't the technical challenges. It wasn't the pipeline complexity or the template versioning. It was getting hundreds of developers to change their habits.

Developers had muscle memory for Jenkins. They knew which buttons to click, which logs to check, how to restart failed builds. Suddenly asking them to learn a completely new interface, new terminology, new workflows? That's a big ask.

I spent as much time on change management as I did on technical implementation. Documentation, training sessions, office hours, Slack channels for questions. The migration succeeded because we treated it as a people problem, not just a technical problem.

Human Change Management

The Numbers That Made It All Worth It

After a year of careful migration, we finally shut down our last Jenkins instance. Infrastructure costs dropped by 60% thanks to on-demand compute. Average pipeline execution time decreased by 40%. Pipeline failure rate dropped from 15% to less than 2%. Developer satisfaction scores increased dramatically.

But the real win? Developers stopped thinking about CI/CD as a problem. It just worked. They could focus on writing code instead of debugging build failures.

This project fundamentally changed how I think about infrastructure migrations. It's not about moving from A to B - it's about reimagining how things should work. The parallel validation approach I developed here became my template for every major migration since.

That's the mark of good infrastructure work - when it becomes invisible, reliable, and just works. After a year of careful migration, that's exactly what we achieved.

Questions People Actually Ask

You know, after sharing this project, I keep getting the same questions. So here are the real answers to the things people actually want to know.