769 words
4 min read

Mastering GitLab CI/CD with Advanced Configuration Techniques

By · Solutions Architect · Docker Captain · IBM Champion
Cover image for the post 'Mastering GitLab CI/CD with Advanced Configuration Techniques'

Forget the glossy dashboards and the slick demos. Real DevOps happens in the trenches, and your .gitlab-ci.yml is the weapon. If you’ve ever sat there at 2AM screaming at a broken pipeline, you already know the deal. GitLab CI/CD is powerful. But only once you stop treating the YAML like a to-do list and start treating it like an automation framework.

This is not another “Hello, pipeline” walkthrough. It’s the stuff that actually makes GitLab CI/CD worth running: cleaner configs, builds that finish before you lose patience, deploys that don’t wake you up. No fluff.

GitLab CI/CD in one sentence#

It’s just code that builds, tests, and ships your other code. Every push. Every merge. Every time you break something.

All of it lives in one file. .gitlab-ci.yml.

What a real pipeline actually looks like#

A lot of the YAML floating around out there reads like someone copied it off Stack Overflow, said a quiet prayer, and hit push. Don’t do that. Here’s how to structure a pipeline you can still maintain six months later.

stages:
- build
- test
- deploy
build_job:
stage: build
script:
- echo "Building the project..."
test_job:
stage: test
script:
- echo "Running tests..."
deploy_job:
stage: deploy
script:
- echo "Deploying the project..."

That’s the skeleton. Clean and linear. Each stage is one phase of the pipeline. Jobs in the same stage run in parallel, assuming your runners can take it. Want a faster pipeline? This is the first lever you pull.

Docker FTW#

If you’re not pinning your jobs to Docker images, you’re running CI in hard mode for no reason.

image: node:20-alpine
build_job:
stage: build
script:
- npm ci
- npm run build

Pick the right image and your builds get reproducible and portable. Sometimes even fast. Just don’t use latest. Not unless you enjoy surprise breakages on a Monday morning.

Artifacts and cache: the fuel CI runs on#

Now let’s make things quick.

Artifacts move data between jobs#

build_job:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/

Cache moves data between pipelines#

cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/

Use both with some care and your pipeline goes from molasses to caffeinated cheetah. Abuse them and you’ll be debugging stale builds in Slack at midnight. Your call.

Modular configs with include#

Once that pipeline file crosses 100 lines, YAML turns into YELL.

So split it up.

include:
- local: ".gitlab-ci/build.yml"
- local: ".gitlab-ci/deploy.yml"
- project: "devops/templates"
file: "/shared/test-suite.yml"

Now the config is maintainable, reusable, testable. Like actual code, which is what it is.

Keep secrets in the vault#

This should be obvious. I’ll say it loud anyway, for the folks in the back.

Never hardcode secrets in your YAML.

variables:
AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY

Manage these in GitLab’s UI, at the project, group, or instance level. Use protected variables for protected branches. Basic hygiene. Don’t be the person who commits prod_db_password: hunter2.

before_script and after_script: your pipeline’s wrapper#

Need to prep or clean up on every run? These are your hooks.

test_job:
stage: test
before_script:
- echo "Setting up..."
script:
- npm test
after_script:
- echo "Tearing down..."

I reach for them to bootstrap test databases, set env vars, pull logs, and rage-log failures. Setup and teardown, the same as you’d write in a test suite.

Smarter pipelines with rules#

Want jobs that fire only when they should? Quit misusing only/except. Use rules like a grown-up.

deploy_prod:
stage: deploy
script:
- ./scripts/deploy-prod.sh
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
when: never

No more deploying off some typo branch by accident.

Real optimization: dynamic variables and better caching#

You can steer pipeline behavior on the fly with job-level variables.

deploy:
stage: deploy
variables:
ENV: "staging"
script:
- ./deploy.sh $ENV

Lean on CI_COMMIT_REF_NAME and the other built-ins to drive environments, image tags, artifact names, whatever you need.

And yes, cache keys matter.

cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- vendor/

One cache per branch keeps builds fast and stops branches from poisoning each other’s state.

TL;DR: how to not suck at GitLab CI#

  • Your .gitlab-ci.yml is real code. Treat it like it
  • Use Docker images, not host dependencies
  • Cache smartly, artifact deliberately
  • Stop repeating yourself. Modularize with include
  • Use rules to make the pipeline conditional and intelligent
  • Secrets go in the GitLab UI, never in version control
  • Optimize for speed, clarity, and safety, in that order

Takeaway#

CI/CD isn’t magic. It’s engineering. And a bad pipeline will quietly eat your hours, your weekends, and whatever’s left of your patience.

So build it right the first time. Start with the basics. Modularize as the thing grows. Automate like your job depends on it, because some days it actually does.

Next step is simple. Open the .gitlab-ci.yml, tear out the duct tape, and make it battle-ready.

And if you’re serious about getting good at this, bookmark GitLab’s CI/CD docs. Then go read them.


Vladimir Mikhalev

Docker Captain  ·  IBM Champion  ·  AWS Community Builder

The Verdict — production-tested analysis on YouTube.

The Verdict

Inconvenient truths about shipping in the AI era

Container security, platform engineering, and the agentic shift — tested in production, argued without the hype. The verdict reaches your inbox the moment there's one worth sending.

Related Posts

Same category
  1. 1
    Docker supply chain hardening — from Scout D to OpenSSF 7.8 on a 730K-pull image
    DevOps & Cloud · How I hardened a 730K-pull public Docker image from Scout grade D to OpenSSF Scorecard 7.8. Multi-stage build, cosign signing, SLSA provenance, non-root default, and the incident that changed how I ship attestations.
  2. 2
    Cloudflare Web Analytics on Astro — Why Removing GA4 Unlocked Lighthouse 100
    DevOps & Cloud · How removing Google Analytics 4 from an Astro site unlocked Lighthouse 100, why Cloudflare Web Analytics replaced it, and what the tradeoffs actually cost.
  3. 3
    Platform Engineering — The Complete, Practical Guide to Building Internal Developer Platforms That Scale
    DevOps & Cloud · A deep, practical guide to Platform Engineering. Learn how to build internal developer platforms, golden paths, GitOps workflows, and scalable cloud foundations.
  4. 4
    Amazon Q vs DevOps Chaos — Can This AI Fix AWS Faster Than You?
    DevOps & Cloud · Fix AWS issues faster with Amazon Q, the AI assistant built for DevOps. Real-world examples, limitations, and how it compares to ChatGPT.

Random Posts

Random
  1. 1
    Install Exchange Server 2019 on Windows Server 2019
    SysAdmin & IT Pro · Step-by-step guide to install Exchange Server 2019 on Windows Server 2019, including prerequisites, Active Directory setup, and admin tips.
  2. 2
    Install Ghost Using Docker Compose
    Self-Hosting · Install Ghost with Docker Compose and Traefik, complete with Let's Encrypt SSL. Launch a secure, self-hosted blogging platform in just a few steps.
  3. 3
    Install Zabbix Using Docker Compose
    Self-Hosting · Step-by-step guide to install Zabbix with Docker Compose using Traefik and Let's Encrypt. Perfect for self-hosted monitoring on Ubuntu Server.
  4. 4
    Install Minecraft on Windows
    SysAdmin & IT Pro · Step-by-step guide on how to install Minecraft Java Edition on Windows. Learn how to download, install, and launch Minecraft quickly and easily.
Mastering GitLab CI/CD with Advanced Configuration Techniques
https://heyvaldemar.com/mastering-gitlab-ci-cd-with-advanced-configuration-techniques/
Author
Vladimir Mikhalev
Published
2024-05-31
License
CC BY-NC-SA 4.0