Ah, CI/CD pipelines - the magical conveyor belts that turn our chaotic code commits into polished production artifacts. Let’s create one that would make even Go’s gopher mascot do a happy dance. I promise this won’t be another “Hello World” tutorial - we’re building a pipeline that actually does useful work while keeping your codebase healthier than a hipster’s kombucha stash.
The Gopher’s Toolbelt: Prerequisites
Before we start our pipeline rave, you’ll need:
- A GitLab account (free tier works fine)
- A Go project that’s at least mildly interesting
- Docker installed (because containers are today’s shipping containers)
- A coffee maker within 10 steps (optional but recommended)
Step 1: Project Setup - Gopher Style
Create .gitlab-ci.yml
in your project root - this is our pipeline’s DNA. Let’s start with something that would make Rob Pike nod approvingly:
image: golang:1.21-alpine
stages:
- dependencies
- build
- test
- lint
- deploy
variables:
GOPROXY: "https://proxy.golang.org"
GOFLAGS: "-mod=readonly"
This foundation gives us Alpine’s slim waistline and proper Go module configuration. The stages represent our pipeline’s lifecycle - from dependency management to deployment.
The Pipeline Symphony
Let’s visualize our masterpiece:
This ensures we don’t deploy code that’s either broken or stylistically offensive. Now let’s populate each stage with jobs that actually earn their keep.
Dependency Management: The Adulting Phase
resolve_dependencies:
stage: dependencies
script:
- go mod download
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .cache/go-build
- go/pkg/mod
This job is like a responsible roommate - it downloads dependencies once and caches them for future runs. The cache key ensures different branches don’t step on each other’s toes.
Building & Testing: Where Rubber Meets Road
build_binary:
stage: build
script:
- go build -v -ldflags "-s -w" -o my-app
artifacts:
paths:
- my-app
Our build job compiles the binary with size optimizations and saves it as an artifact. Now for the test suite:
run_tests:
stage: test
script:
- go test -v -race ./...
coverage: '/^coverage: \d+\.\d+\% of statements/'
artifacts:
reports:
cobertura: coverage.xml
This runs tests with race detection and captures coverage data. The coverage
regex makes GitLab display pretty coverage badges - because metrics matter!
Linting: The Code Spa Treatment
golangci_lint:
stage: lint
image: golangci/golangci-lint:latest
script:
- golangci-lint run --out-format checkstyle ./... > report.xml
artifacts:
reports:
codequality: report.xml
Using the official linter image, this job gives your code a full spa treatment. The checkstyle format integrates nicely with GitLab’s code quality reports.
Deployment: Release the Gopher!
deploy_production:
stage: deploy
image: docker:20.10
services:
- docker:20.10-dind
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
script:
- docker build -t $IMAGE_TAG .
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker push $IMAGE_TAG
only:
- main
This Docker-powered deployment job only runs on main branch commits. It builds, tags, and pushes your containerized Go app to GitLab’s registry. Pro tip: Add --pull
to your build args to avoid stale base images.
Pipeline Optimizations: Turbo Mode
- Parallel Testing: Split your test suite across multiple jobs using
parallel
andgo test -shuffle
- Cache Warming: Add a scheduled pipeline that updates dependencies nightly
- Multi-stage Builds: Use Docker’s
--target
to create lean production images - Secret Management: Use GitLab’s masked variables for credentials
- Pipeline Triggering: Add
rules
to prevent unnecessary builds on docs changes
When Things Go Wrong: Debugging Tips
- Shell Access: Use
SSH into running jobs
for live debugging - Artifact Forensics: Download build artifacts to inspect binaries
- Local Testing: Run
gitlab-runner exec docker your-job
for local validation - Dependency Visualization: Add
go mod graph
job to track module relationships
The Final Countdown
Remember: A good pipeline is like a reliable friend - it tells you when something’s wrong but doesn’t nag about minor issues. Our final pipeline will:
- Keep dependencies fresh
- Maintain code quality standards
- Ensure test coverage
- Produce production-ready artifacts
- Deploy safely and repeatably Now go forth and pipeline! And remember - if your CI takes longer than your coffee break, you’re doing it wrong. Keep Calm and CI/CD On!