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
    Terraform MCP server GA: the Apply Gate your auditor will ask about
    DevOps & Cloud · HashiCorp's Terraform MCP server is GA and IBM Bob can write production IaC. ENABLE_TF_OPERATIONS separates a safe assistant from autonomous apply.
  2. 2
    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.
  3. 3
    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.
  4. 4
    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.

Random Posts

Random
  1. 1
    The 80th Anniversary of the Deportation of the Crimean Tatars
    Opinion & Culture · Marking 80 years since the 1944 deportation of Crimean Tatars by Stalin's regime. Explore the tragedy, its impact, and its echoes in modern-day Crimea.
  2. 2
    Install Bitbucket Using Docker Compose
    Self-Hosting · Learn how to install Bitbucket using Docker Compose and Traefik on your server. Step-by-step guide with HTTPS setup and admin configuration for Git hosting.
  3. 3
    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.
  4. 4
    Install Outline and Keycloak Using Docker Compose
    Self-Hosting · Deploy Outline with Keycloak SSO, Traefik, and MinIO on Ubuntu using Docker Compose. A complete, secure wiki setup with SSL, access control, and cloud storage.
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