Manual deployment on Friday at 5:00 PM — everyone knows it, nobody wants to repeat it. Automated CI/CD pipeline eliminates human errors, shortens the feedback loop, and allows deploying dozens of times a day with confidence. Let’s show how to build one.
Anatomy of a Modern CI/CD Pipeline¶
A pipeline isn’t just “build and deploy”. A quality pipeline has clearly defined stages, where each phase must pass before the next one starts:
- Commit stage — lint, unit tests, compile (< 5 min)
- Build stage — Docker image build, artifact packaging
- Security stage — SAST, dependency scanning, container scanning
- Test stage — integration tests, API tests, e2e tests
- Staging deploy — automatic deployment to staging environment
- Production deploy — manual approval + automated rollout
GitLab CI — Pipeline as Code¶
GitLab CI defines the pipeline in a .gitlab-ci.yml file directly in the repository. Advantage: the pipeline is versioned together with the code.
stages:
- test
- build
- security
- deploy-staging
- deploy-prod
unit-tests:
stage: test
image: node:10-alpine
script:
- npm ci
- npm run lint
- npm run test:unit -- --coverage
artifacts:
reports:
junit: coverage/junit.xml
only:
- merge_requests
- master
build-image:
stage: build
image: docker:stable
services:
- docker:dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- master
dependency-scan:
stage: security
image: node:10-alpine
script:
- npm audit --audit-level=high
allow_failure: true
deploy-staging:
stage: deploy-staging
script:
- kubectl set image deployment/api api=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/api --timeout=120s
environment:
name: staging
only:
- master
deploy-production:
stage: deploy-prod
script:
- kubectl set image deployment/api api=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- kubectl rollout status deployment/api --timeout=300s
environment:
name: production
when: manual
only:
- master
Jenkins — Flexible Veteran¶
Jenkins is still dominant in enterprise environments. Jenkinsfile (declarative pipeline) brings pipeline-as-code to the Jenkins world as well:
pipeline {
agent { docker { image 'node:10-alpine' } }
stages {
stage('Test') {
steps {
sh 'npm ci'
sh 'npm run test:unit'
}
post {
always { junit 'coverage/junit.xml' }
}
}
stage('Build') {
steps {
sh "docker build -t api:${env.BUILD_NUMBER} ."
sh "docker push registry.company.com/api:${env.BUILD_NUMBER}"
}
}
stage('Deploy Staging') {
steps {
sh "kubectl set image deployment/api api=registry.company.com/api:${env.BUILD_NUMBER}"
}
}
stage('Deploy Production') {
input { message 'Deploy to production?' }
steps {
sh "kubectl set image deployment/api api=registry.company.com/api:${env.BUILD_NUMBER}"
}
}
}
}
GitLab CI vs Jenkins — What to Choose?¶
- GitLab CI: better developer experience, integrated with GitLab repository, simpler configuration, shared runners for free. Ideal for small to medium teams.
- Jenkins: more flexible, huge plugin ecosystem (1500+), better for complex enterprise pipelines with custom steps. Requires Jenkins server management.
- 2018 Trend: GitLab CI is growing rapidly, Jenkins maintains position due to legacy installations and enterprise adoption.
Security in Pipeline — Shift Left¶
Security checks belong in the pipeline, not at the end of the development cycle:
- SAST (Static Application Security Testing) — SonarQube, Bandit (Python), ESLint security plugin
- Dependency scanning — npm audit, OWASP Dependency Check, Snyk
- Container scanning — Clair, Trivy for Docker image scanning
- Secret detection — git-secrets, truffleHog for detecting committed credentials
Important: the security stage should not block deployment on day one. Start with allow_failure: true and gradually tighten as the team resolves existing findings.
Zero-Downtime Deployment¶
Kubernetes rolling update is the foundation, but it’s not enough. For true zero-downtime you need:
- Readiness probes — Kubernetes sends traffic only when the pod is ready
- Graceful shutdown — application completes running requests before stopping
- Database migrations — backward-compatible migrations (expand-contract pattern)
- Feature flags — separate deployment from release (LaunchDarkly, unleash)
Pipeline Metrics¶
What you don’t measure, you don’t improve. Track:
- Lead time — time from commit to production deployment
- Deployment frequency — how many times per day/week you deploy
- MTTR — mean time to recovery after failed deployment
- Change failure rate — percentage of deployments requiring hotfix/rollback
These four metrics come from DORA (DevOps Research and Assessment) research and correlate with overall organization performance.
Pipeline is an Investment That Pays Back in Weeks¶
Building a quality CI/CD pipeline takes 2–5 days. The return comes immediately — fewer bugs in production, faster feedback for developers, less stress during releases. Start simple (test + build + deploy) and iterate. The perfect pipeline doesn’t exist, but any automated pipeline is better than none.
Need help with implementation?
Our experts can help with design, implementation, and operations. From architecture to production.
Contact us