{"product_id":"gitlab-ci-cd-pipeline-templates","title":"GitLab CI\/CD Pipeline Templates","description":"\u003ch3\u003eGitLab CI\/CD Pipeline Templates\u003c\/h3\u003e\n\u003cp\u003eGitLab CI has a unique advantage over GitHub Actions: the runner infrastructure is yours. But that advantage becomes a liability when the team treats runners as cattle they never monitor. At an energy sector client, a shared GitLab runner had 3GB of Docker images from 2019 filling its disk. Every pipeline spent 4 minutes in \u003ccode\u003edocker pull\u003c\/code\u003e because the cache was corrupted. Nobody investigated because \"pipelines are just slow.\" This template includes runner health monitoring and cache management that prevents that decay.\u003c\/p\u003e\n\n\u003cp\u003eThis \u003ccode\u003e.gitlab-ci.yml\u003c\/code\u003e implements a multi-stage pipeline with DAG dependencies, environment promotion, and security scanning that I have deployed for teams processing sensitive infrastructure data.\u003c\/p\u003e\n\n\u003ch3\u003ePipeline Stages\u003c\/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cstrong\u003estages: [lint, test, security, build, deploy-dev, deploy-staging, deploy-prod]\u003c\/strong\u003e — DAG dependencies via \u003ccode\u003eneeds:\u003c\/code\u003e keywords allow parallel execution where stages are independent. Lint and security run simultaneously.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003elint\u003c\/strong\u003e — \u003ccode\u003eimage: golangci\/golangci-lint:v1.57\u003c\/code\u003e or language-equivalent. Runs in under 60 seconds. Cache: \u003ccode\u003e$CI_COMMIT_REF_SLUG\u003c\/code\u003e keyed.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003etest\u003c\/strong\u003e — Parallel jobs via \u003ccode\u003eparallel: 4\u003c\/code\u003e with test splitting. \u003ccode\u003eservices: [postgres:16, redis:7]\u003c\/code\u003e for integration tests. Coverage extracted via regex and displayed in MR widget.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003esecurity\u003c\/strong\u003e — \u003ccode\u003einclude: Security\/SAST.gitlab-ci.yml\u003c\/code\u003e and \u003ccode\u003eSecurity\/Secret-Detection.gitlab-ci.yml\u003c\/code\u003e from GitLab templates. Container scanning via \u003ccode\u003eSecurity\/Container-Scanning.gitlab-ci.yml\u003c\/code\u003e. Results appear in the MR security widget.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003ebuild\u003c\/strong\u003e — \u003ccode\u003edocker build\u003c\/code\u003e with Kaniko (\u003ccode\u003egcr.io\/kaniko-project\/executor:v1.22.0\u003c\/code\u003e) for rootless builds in shared runners. Push to GitLab Container Registry with \u003ccode\u003e$CI_COMMIT_SHA\u003c\/code\u003e tag.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003edeploy-dev\u003c\/strong\u003e — \u003ccode\u003eenvironment: dev\u003c\/code\u003e with \u003ccode\u003eauto_stop_in: 1 week\u003c\/code\u003e. Deploys via Helm to the dev cluster. Runs \u003ccode\u003eonly: [develop]\u003c\/code\u003e.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003edeploy-staging\u003c\/strong\u003e — \u003ccode\u003eenvironment: staging\u003c\/code\u003e with \u003ccode\u003ewhen: manual\u003c\/code\u003e. Requires MR approval before deploy button is clickable. Runs integration test suite post-deploy.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003edeploy-prod\u003c\/strong\u003e — \u003ccode\u003eenvironment: production\u003c\/code\u003e with \u003ccode\u003ewhen: manual\u003c\/code\u003e and \u003ccode\u003eallow_failure: false\u003c\/code\u003e. Protected environment requiring two approvals. Canary deployment with \u003ccode\u003ekubectl set image\u003c\/code\u003e at 10% weight.\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eSecurity Gates\u003c\/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cstrong\u003eGitLab SAST\u003c\/strong\u003e — Built-in analyzers for 15+ languages. Runs automatically via template inclusion. Findings block MR merge when severity is CRITICAL.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eSecret Detection\u003c\/strong\u003e — Scans for API keys, tokens, and credentials in code and commit history. Pre-receive hook blocks pushes containing detected secrets.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eContainer Scanning\u003c\/strong\u003e — Trivy-based scanner runs against built images. Results integrated into GitLab's vulnerability dashboard.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eLicense Compliance\u003c\/strong\u003e — \u003ccode\u003eSecurity\/License-Scanning.gitlab-ci.yml\u003c\/code\u003e checks dependencies against approved license policies.\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch3\u003eWhat Breaks First\u003c\/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cstrong\u003eRunner disk full from Docker layers\u003c\/strong\u003e — Shared runners accumulate Docker images and build caches. Fix: schedule \u003ccode\u003edocker system prune -af --filter \"until=48h\"\u003c\/code\u003e as a cron job on every runner.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eCache key collision between branches\u003c\/strong\u003e — \u003ccode\u003ecache: key: $CI_COMMIT_REF_SLUG\u003c\/code\u003e means branches with similar names share caches. Fix: include \u003ccode\u003e$CI_JOB_NAME\u003c\/code\u003e in the cache key.\u003c\/li\u003e\n\u003cli\u003e\n\u003cstrong\u003eKaniko context size timeout\u003c\/strong\u003e — Large repositories with node_modules or vendor directories cause Kaniko to timeout building the context. Fix: add a \u003ccode\u003e.dockerignore\u003c\/code\u003e that excludes everything except the build output and required files.\u003c\/li\u003e\n\u003c\/ul\u003e","brand":"Citadel Cloud Management","offers":[{"title":"Default Title","offer_id":54890411196707,"sku":"CCM-DEV-007","price":39.0,"currency_code":"USD","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0979\/8539\/7027\/files\/citadel-devops-product_fa6cd903-0251-47b6-9f6f-880fadabd086.jpg?v=1775138091","url":"https:\/\/citadel-cloud-management.myshopify.com\/products\/gitlab-ci-cd-pipeline-templates","provider":"Citadel Cloud Management","version":"1.0","type":"link"}