Introduction
CI/CD (Continuous Integration/Continuous Deployment) automates the software delivery process from code commit to production deployment. This automation reduces manual errors, speeds up releases, and improves software quality.
This guide visualizes the complete CI/CD pipeline:
- Code Commit: Developer pushes code
- Continuous Integration: Automated testing and building
- Continuous Deployment: Automated deployment to production
- Quality Gates: Checkpoints ensuring code quality
- Rollback Mechanisms: Handling deployment failures
Part 1: Complete CI/CD Pipeline Overview
End-to-End Flow
%%{init: {'theme':'dark', 'themeVariables': {'primaryTextColor':'#e5e7eb','secondaryTextColor':'#e5e7eb','tertiaryTextColor':'#e5e7eb','textColor':'#e5e7eb','nodeTextColor':'#e5e7eb','edgeLabelText':'#e5e7eb','clusterTextColor':'#e5e7eb','actorTextColor':'#e5e7eb'}}}%%
flowchart TD
Start([Developer writes code
commits changes]) --> Push[git push origin main] Push --> Webhook[Git Provider Webhook
Triggers CI/CD pipeline] Webhook --> Checkout[Stage 1: Checkout
Clone repository
Fetch dependencies] Checkout --> Lint[Stage 2: Lint
Check code style
ESLint, Prettier, golangci-lint] Lint --> LintResult{Linting
passed?} LintResult -->|No| LintFail[❌ Pipeline Failed
Notify developer
Fix linting errors] LintResult -->|Yes| UnitTest[Stage 3: Unit Tests
Run test suite
Generate coverage report] UnitTest --> TestResult{Tests
passed?} TestResult -->|No| TestFail[❌ Pipeline Failed
Some tests failed
Coverage too low] TestResult -->|Yes| Build[Stage 4: Build
Compile application
Build Docker image] Build --> BuildResult{Build
successful?} BuildResult -->|No| BuildFail[❌ Pipeline Failed
Build errors
Dependency issues] BuildResult -->|Yes| IntegTest[Stage 5: Integration Tests
Test with real dependencies
Database, APIs, etc.] IntegTest --> IntegResult{Integration
tests passed?} IntegResult -->|No| IntegFail[❌ Pipeline Failed
Integration issues
Service communication errors] IntegResult -->|Yes| Security[Stage 6: Security Scan
Scan for vulnerabilities
OWASP, Snyk, Trivy] Security --> SecResult{Security
checks passed?} SecResult -->|No| SecFail[❌ Pipeline Failed
Security vulnerabilities found
Fix before deploying] SecResult -->|Yes| Push2Registry[Stage 7: Push Image
Tag: myapp:abc123
Push to container registry] Push2Registry --> DeployStaging[Stage 8: Deploy to Staging
kubectl apply -f staging/
Run smoke tests] DeployStaging --> SmokeTest[Stage 9: Smoke Tests
Test critical paths
Health checks
Basic functionality] SmokeTest --> SmokeResult{Smoke tests
passed?} SmokeResult -->|No| StagingFail[❌ Pipeline Failed
Staging deployment issues
Rollback staging] SmokeResult -->|Yes| Approval{Manual
approval
required?} Approval -->|Yes| WaitApproval[⏸️ Waiting for Approval
Notify team lead
Review changes] WaitApproval --> ApprovalDecision{Approved?} ApprovalDecision -->|No| Rejected[❌ Deployment Rejected
Not ready for production] ApprovalDecision -->|Yes| DeployProd Approval -->|No| DeployProd[Stage 10: Deploy to Production
Rolling update
Or blue-green deployment] DeployProd --> ProdHealth{Production
healthy?} ProdHealth -->|No| AutoRollback[❌ Auto-Rollback
Revert to previous version
Alert on-call team] ProdHealth -->|Yes| Success[✅ Deployment Successful!
Monitor metrics
Notify team
Update status] style LintFail fill:#7f1d1d,stroke:#ef4444 style TestFail fill:#7f1d1d,stroke:#ef4444 style BuildFail fill:#7f1d1d,stroke:#ef4444 style IntegFail fill:#7f1d1d,stroke:#ef4444 style SecFail fill:#7f1d1d,stroke:#ef4444 style StagingFail fill:#7f1d1d,stroke:#ef4444 style AutoRollback fill:#7f1d1d,stroke:#ef4444 style Success fill:#064e3b,stroke:#10b981 style WaitApproval fill:#78350f,stroke:#f59e0b
commits changes]) --> Push[git push origin main] Push --> Webhook[Git Provider Webhook
Triggers CI/CD pipeline] Webhook --> Checkout[Stage 1: Checkout
Clone repository
Fetch dependencies] Checkout --> Lint[Stage 2: Lint
Check code style
ESLint, Prettier, golangci-lint] Lint --> LintResult{Linting
passed?} LintResult -->|No| LintFail[❌ Pipeline Failed
Notify developer
Fix linting errors] LintResult -->|Yes| UnitTest[Stage 3: Unit Tests
Run test suite
Generate coverage report] UnitTest --> TestResult{Tests
passed?} TestResult -->|No| TestFail[❌ Pipeline Failed
Some tests failed
Coverage too low] TestResult -->|Yes| Build[Stage 4: Build
Compile application
Build Docker image] Build --> BuildResult{Build
successful?} BuildResult -->|No| BuildFail[❌ Pipeline Failed
Build errors
Dependency issues] BuildResult -->|Yes| IntegTest[Stage 5: Integration Tests
Test with real dependencies
Database, APIs, etc.] IntegTest --> IntegResult{Integration
tests passed?} IntegResult -->|No| IntegFail[❌ Pipeline Failed
Integration issues
Service communication errors] IntegResult -->|Yes| Security[Stage 6: Security Scan
Scan for vulnerabilities
OWASP, Snyk, Trivy] Security --> SecResult{Security
checks passed?} SecResult -->|No| SecFail[❌ Pipeline Failed
Security vulnerabilities found
Fix before deploying] SecResult -->|Yes| Push2Registry[Stage 7: Push Image
Tag: myapp:abc123
Push to container registry] Push2Registry --> DeployStaging[Stage 8: Deploy to Staging
kubectl apply -f staging/
Run smoke tests] DeployStaging --> SmokeTest[Stage 9: Smoke Tests
Test critical paths
Health checks
Basic functionality] SmokeTest --> SmokeResult{Smoke tests
passed?} SmokeResult -->|No| StagingFail[❌ Pipeline Failed
Staging deployment issues
Rollback staging] SmokeResult -->|Yes| Approval{Manual
approval
required?} Approval -->|Yes| WaitApproval[⏸️ Waiting for Approval
Notify team lead
Review changes] WaitApproval --> ApprovalDecision{Approved?} ApprovalDecision -->|No| Rejected[❌ Deployment Rejected
Not ready for production] ApprovalDecision -->|Yes| DeployProd Approval -->|No| DeployProd[Stage 10: Deploy to Production
Rolling update
Or blue-green deployment] DeployProd --> ProdHealth{Production
healthy?} ProdHealth -->|No| AutoRollback[❌ Auto-Rollback
Revert to previous version
Alert on-call team] ProdHealth -->|Yes| Success[✅ Deployment Successful!
Monitor metrics
Notify team
Update status] style LintFail fill:#7f1d1d,stroke:#ef4444 style TestFail fill:#7f1d1d,stroke:#ef4444 style BuildFail fill:#7f1d1d,stroke:#ef4444 style IntegFail fill:#7f1d1d,stroke:#ef4444 style SecFail fill:#7f1d1d,stroke:#ef4444 style StagingFail fill:#7f1d1d,stroke:#ef4444 style AutoRollback fill:#7f1d1d,stroke:#ef4444 style Success fill:#064e3b,stroke:#10b981 style WaitApproval fill:#78350f,stroke:#f59e0b
Part 2: Continuous Integration (CI) Stages
CI Pipeline Detailed Flow
%%{init: {'theme':'dark', 'themeVariables': {'primaryTextColor':'#e5e7eb','secondaryTextColor':'#e5e7eb','tertiaryTextColor':'#e5e7eb','textColor':'#e5e7eb','nodeTextColor':'#e5e7eb','edgeLabelText':'#e5e7eb','clusterTextColor':'#e5e7eb','actorTextColor':'#e5e7eb'}}}%%
sequenceDiagram
participant Dev as Developer
participant Git as Git Repository
participant CI as CI Server
participant Docker as Docker Registry
participant Notify as Slack/Email
Dev->>Git: git push origin feature/new-api
Note over Git: Webhook triggered
on push event Git->>CI: Trigger pipeline:
Branch: feature/new-api
Commit: abc123
Author: [email protected] CI->>CI: Create build environment
Ubuntu 22.04 container CI->>Git: git clone --depth 1
Checkout abc123 Note over CI: Stage 1: Setup CI->>CI: Install dependencies
npm install
go mod download Note over CI: Stage 2: Code Quality CI->>CI: Run linter
eslint src/
golangci-lint run alt Linting Failed CI->>Notify: ❌ Linting failed
26 issues found
Fix formatting CI-->>Dev: Pipeline failed end Note over CI: Stage 3: Unit Testing CI->>CI: Run unit tests
npm test
go test ./... CI->>CI: Generate coverage report
Coverage: 87% alt Tests Failed or Low Coverage CI->>Notify: ❌ Tests failed
5 tests failing
Coverage: 72% < 80% CI-->>Dev: Pipeline failed end Note over CI: Stage 4: Build CI->>CI: Build application
npm run build
go build -o app CI->>CI: Build Docker image
docker build -t myapp:abc123 alt Build Failed CI->>Notify: ❌ Build failed
Compilation errors CI-->>Dev: Pipeline failed end Note over CI: Stage 5: Integration Tests CI->>CI: Start test dependencies
docker-compose up -d
postgres, redis CI->>CI: Run integration tests
Test database connections
Test API endpoints CI->>CI: Stop test services
docker-compose down alt Integration Tests Failed CI->>Notify: ❌ Integration tests failed
Database connection timeout CI-->>Dev: Pipeline failed end Note over CI: Stage 6: Security Scanning CI->>CI: Scan dependencies
npm audit
snyk test CI->>CI: Scan Docker image
trivy image myapp:abc123 alt Security Issues Found CI->>Notify: ⚠️ Security issues
3 high severity CVEs
Update dependencies CI-->>Dev: Pipeline failed end Note over CI: All checks passed! ✓ CI->>Docker: docker push myapp:abc123
Tag: myapp:latest Docker-->>CI: Image pushed successfully CI->>Notify: ✅ Build successful!
Image: myapp:abc123
Ready for deployment CI-->>Dev: Pipeline succeeded
Duration: 8m 32s
on push event Git->>CI: Trigger pipeline:
Branch: feature/new-api
Commit: abc123
Author: [email protected] CI->>CI: Create build environment
Ubuntu 22.04 container CI->>Git: git clone --depth 1
Checkout abc123 Note over CI: Stage 1: Setup CI->>CI: Install dependencies
npm install
go mod download Note over CI: Stage 2: Code Quality CI->>CI: Run linter
eslint src/
golangci-lint run alt Linting Failed CI->>Notify: ❌ Linting failed
26 issues found
Fix formatting CI-->>Dev: Pipeline failed end Note over CI: Stage 3: Unit Testing CI->>CI: Run unit tests
npm test
go test ./... CI->>CI: Generate coverage report
Coverage: 87% alt Tests Failed or Low Coverage CI->>Notify: ❌ Tests failed
5 tests failing
Coverage: 72% < 80% CI-->>Dev: Pipeline failed end Note over CI: Stage 4: Build CI->>CI: Build application
npm run build
go build -o app CI->>CI: Build Docker image
docker build -t myapp:abc123 alt Build Failed CI->>Notify: ❌ Build failed
Compilation errors CI-->>Dev: Pipeline failed end Note over CI: Stage 5: Integration Tests CI->>CI: Start test dependencies
docker-compose up -d
postgres, redis CI->>CI: Run integration tests
Test database connections
Test API endpoints CI->>CI: Stop test services
docker-compose down alt Integration Tests Failed CI->>Notify: ❌ Integration tests failed
Database connection timeout CI-->>Dev: Pipeline failed end Note over CI: Stage 6: Security Scanning CI->>CI: Scan dependencies
npm audit
snyk test CI->>CI: Scan Docker image
trivy image myapp:abc123 alt Security Issues Found CI->>Notify: ⚠️ Security issues
3 high severity CVEs
Update dependencies CI-->>Dev: Pipeline failed end Note over CI: All checks passed! ✓ CI->>Docker: docker push myapp:abc123
Tag: myapp:latest Docker-->>CI: Image pushed successfully CI->>Notify: ✅ Build successful!
Image: myapp:abc123
Ready for deployment CI-->>Dev: Pipeline succeeded
Duration: 8m 32s
GitHub Actions CI Configuration
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Job 1: Code Quality Checks
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run Prettier
run: npm run format:check
# Job 2: Unit Tests
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test -- --coverage
- name: Check coverage threshold
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% is below 80%"
exit 1
fi
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
# Job 3: Build
build:
runs-on: ubuntu-latest
needs: [lint, test] # Wait for lint and test to pass
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix={{branch}}-
type=ref,event=branch
type=ref,event=pr
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Job 4: Integration Tests
integration-test:
runs-on: ubuntu-latest
needs: build
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run integration tests
run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
REDIS_URL: redis://localhost:6379
# Job 5: Security Scan
security:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: npm audit --audit-level=high
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
- name: Scan Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
Part 3: Continuous Deployment (CD) Stages
Deployment Pipeline Flow
%%{init: {'theme':'dark', 'themeVariables': {'primaryTextColor':'#e5e7eb','secondaryTextColor':'#e5e7eb','tertiaryTextColor':'#e5e7eb','textColor':'#e5e7eb','nodeTextColor':'#e5e7eb','edgeLabelText':'#e5e7eb','clusterTextColor':'#e5e7eb','actorTextColor':'#e5e7eb'}}}%%
flowchart TD
Start([CI Pipeline Passed
Image ready: myapp:abc123]) --> DeployDecision{Which
branch?} DeployDecision -->|feature/*| SkipDeploy[Skip deployment
CI only for
feature branches] DeployDecision -->|develop| DeployDev[Deploy to Dev Environment
Namespace: dev
Auto-deploy on push] DeployDecision -->|main| DeployStaging[Deploy to Staging
Namespace: staging
Auto-deploy on push] DeployDev --> DevSmoke[Run smoke tests
Basic health checks] DevSmoke --> DevDone[✅ Dev deployment complete] DeployStaging --> UpdateManifest[Update Kubernetes manifests
image: myapp:abc123
Apply configuration] UpdateManifest --> ApplyStaging[kubectl apply -f k8s/staging/
Create/Update resources
Wait for rollout] ApplyStaging --> WaitReady{All pods
ready?} WaitReady -->|No timeout| CheckHealth[Check pod status
kubectl get pods -n staging] CheckHealth --> HealthStatus{Healthy?} HealthStatus -->|No| RollbackStaging[❌ Rollback staging
kubectl rollout undo
deployment myapp -n staging] RollbackStaging --> NotifyFail[Notify team:
Staging deployment failed
Check logs and fix] HealthStatus -->|Yes| StagingSmoke[Run staging smoke tests
- Health endpoint
- Critical API endpoints
- Database connectivity] StagingSmoke --> SmokePass{Smoke tests
passed?} SmokePass -->|No| RollbackStaging SmokePass -->|Yes| StagingReady[✅ Staging Ready
All tests passed
Ready for production] StagingReady --> ApprovalGate{Require manual
approval?} ApprovalGate -->|Yes| WaitApproval[⏸️ Wait for approval
Create deployment request
Notify reviewers] WaitApproval --> ReviewDecision{Approved
by reviewer?} ReviewDecision -->|No| Rejected[❌ Deployment rejected
Feedback provided
Make changes] ReviewDecision -->|Yes| DeployProd ApprovalGate -->|No| DeployProd[Deploy to Production
Namespace: production
Strategy: Rolling update] DeployProd --> BackupProd[Create backup:
- Current deployment state
- Database snapshot
- Config backup] BackupProd --> ApplyProd[kubectl apply -f k8s/prod/
Rolling update:
maxSurge: 1
maxUnavailable: 0] ApplyProd --> MonitorRollout[Monitor rollout status
kubectl rollout status
deployment myapp -n production] MonitorRollout --> ProdHealth{All new pods
healthy?} ProdHealth -->|No| AutoRollback[🚨 Auto-rollback triggered
kubectl rollout undo
Restore previous version] AutoRollback --> AlertTeam[Alert on-call team
PagerDuty notification
Production incident] ProdHealth -->|Yes| ProdMonitor[Monitor production metrics
- Error rates
- Latency
- Business KPIs] ProdMonitor --> MetricsOK{Metrics
healthy for
10 minutes?} MetricsOK -->|No| AutoRollback MetricsOK -->|Yes| Complete[✅ Deployment Complete!
Production healthy
New version live
Update status page] Complete --> CleanupOld[Cleanup old resources
Remove old replica sets
Prune old images] style SkipDeploy fill:#1e3a8a,stroke:#3b82f6 style WaitApproval fill:#78350f,stroke:#f59e0b style RollbackStaging fill:#7f1d1d,stroke:#ef4444 style AutoRollback fill:#7f1d1d,stroke:#ef4444 style Complete fill:#064e3b,stroke:#10b981 style DevDone fill:#064e3b,stroke:#10b981
Image ready: myapp:abc123]) --> DeployDecision{Which
branch?} DeployDecision -->|feature/*| SkipDeploy[Skip deployment
CI only for
feature branches] DeployDecision -->|develop| DeployDev[Deploy to Dev Environment
Namespace: dev
Auto-deploy on push] DeployDecision -->|main| DeployStaging[Deploy to Staging
Namespace: staging
Auto-deploy on push] DeployDev --> DevSmoke[Run smoke tests
Basic health checks] DevSmoke --> DevDone[✅ Dev deployment complete] DeployStaging --> UpdateManifest[Update Kubernetes manifests
image: myapp:abc123
Apply configuration] UpdateManifest --> ApplyStaging[kubectl apply -f k8s/staging/
Create/Update resources
Wait for rollout] ApplyStaging --> WaitReady{All pods
ready?} WaitReady -->|No timeout| CheckHealth[Check pod status
kubectl get pods -n staging] CheckHealth --> HealthStatus{Healthy?} HealthStatus -->|No| RollbackStaging[❌ Rollback staging
kubectl rollout undo
deployment myapp -n staging] RollbackStaging --> NotifyFail[Notify team:
Staging deployment failed
Check logs and fix] HealthStatus -->|Yes| StagingSmoke[Run staging smoke tests
- Health endpoint
- Critical API endpoints
- Database connectivity] StagingSmoke --> SmokePass{Smoke tests
passed?} SmokePass -->|No| RollbackStaging SmokePass -->|Yes| StagingReady[✅ Staging Ready
All tests passed
Ready for production] StagingReady --> ApprovalGate{Require manual
approval?} ApprovalGate -->|Yes| WaitApproval[⏸️ Wait for approval
Create deployment request
Notify reviewers] WaitApproval --> ReviewDecision{Approved
by reviewer?} ReviewDecision -->|No| Rejected[❌ Deployment rejected
Feedback provided
Make changes] ReviewDecision -->|Yes| DeployProd ApprovalGate -->|No| DeployProd[Deploy to Production
Namespace: production
Strategy: Rolling update] DeployProd --> BackupProd[Create backup:
- Current deployment state
- Database snapshot
- Config backup] BackupProd --> ApplyProd[kubectl apply -f k8s/prod/
Rolling update:
maxSurge: 1
maxUnavailable: 0] ApplyProd --> MonitorRollout[Monitor rollout status
kubectl rollout status
deployment myapp -n production] MonitorRollout --> ProdHealth{All new pods
healthy?} ProdHealth -->|No| AutoRollback[🚨 Auto-rollback triggered
kubectl rollout undo
Restore previous version] AutoRollback --> AlertTeam[Alert on-call team
PagerDuty notification
Production incident] ProdHealth -->|Yes| ProdMonitor[Monitor production metrics
- Error rates
- Latency
- Business KPIs] ProdMonitor --> MetricsOK{Metrics
healthy for
10 minutes?} MetricsOK -->|No| AutoRollback MetricsOK -->|Yes| Complete[✅ Deployment Complete!
Production healthy
New version live
Update status page] Complete --> CleanupOld[Cleanup old resources
Remove old replica sets
Prune old images] style SkipDeploy fill:#1e3a8a,stroke:#3b82f6 style WaitApproval fill:#78350f,stroke:#f59e0b style RollbackStaging fill:#7f1d1d,stroke:#ef4444 style AutoRollback fill:#7f1d1d,stroke:#ef4444 style Complete fill:#064e3b,stroke:#10b981 style DevDone fill:#064e3b,stroke:#10b981
Part 4: Quality Gates
Quality Gate Decision Flow
%%{init: {'theme':'dark', 'themeVariables': {'primaryTextColor':'#e5e7eb','secondaryTextColor':'#e5e7eb','tertiaryTextColor':'#e5e7eb','textColor':'#e5e7eb','nodeTextColor':'#e5e7eb','edgeLabelText':'#e5e7eb','clusterTextColor':'#e5e7eb','actorTextColor':'#e5e7eb'}}}%%
flowchart TD
Start([Code ready to deploy]) --> Gate1{Quality Gate 1:
Code Quality} Gate1 --> CheckLint[Check Linting
ESLint, Prettier] Gate1 --> CheckComplexity[Check Complexity
Cyclomatic complexity
< 10 per function] Gate1 --> CheckDuplication[Check Duplication
Code duplication < 3%] CheckLint --> LintScore{Pass?} CheckComplexity --> ComplexScore{Pass?} CheckDuplication --> DupScore{Pass?} LintScore -->|No| Fail1[❌ Gate 1 Failed] ComplexScore -->|No| Fail1 DupScore -->|No| Fail1 LintScore -->|Yes| Gate2{Quality Gate 2:
Testing} ComplexScore -->|Yes| Gate2 DupScore -->|Yes| Gate2 Gate2 --> CheckCoverage[Check Coverage
Line coverage >= 80%
Branch coverage >= 75%] Gate2 --> CheckTests[All Tests Pass
Unit + Integration] Gate2 --> CheckPerf[Performance Tests
Response time < baseline] CheckCoverage --> CovScore{Pass?} CheckTests --> TestScore{Pass?} CheckPerf --> PerfScore{Pass?} CovScore -->|No| Fail2[❌ Gate 2 Failed] TestScore -->|No| Fail2 PerfScore -->|No| Fail2 CovScore -->|Yes| Gate3{Quality Gate 3:
Security} TestScore -->|Yes| Gate3 PerfScore -->|Yes| Gate3 Gate3 --> CheckVuln[Scan Vulnerabilities
No high/critical CVEs] Gate3 --> CheckSecrets[Check for Secrets
No hardcoded credentials] Gate3 --> CheckDeps[Dependency Check
All deps up-to-date] CheckVuln --> VulnScore{Pass?} CheckSecrets --> SecretScore{Pass?} CheckDeps --> DepScore{Pass?} VulnScore -->|No| Fail3[❌ Gate 3 Failed] SecretScore -->|No| Fail3 DepScore -->|No| Fail3 VulnScore -->|Yes| Gate4{Quality Gate 4:
Production Readiness} SecretScore -->|Yes| Gate4 DepScore -->|Yes| Gate4 Gate4 --> CheckHealth[Health Checks
Liveness + Readiness] Gate4 --> CheckResources[Resource Limits
CPU + Memory defined] Gate4 --> CheckDocs[Documentation
README + API docs] CheckHealth --> HealthScore{Pass?} CheckResources --> ResScore{Pass?} CheckDocs --> DocScore{Pass?} HealthScore -->|No| Fail4[❌ Gate 4 Failed] ResScore -->|No| Fail4 DocScore -->|No| Fail4 HealthScore -->|Yes| AllGates[✅ All Quality Gates Passed!
Ready for deployment] ResScore -->|Yes| AllGates DocScore -->|Yes| AllGates Fail1 --> Block[Block deployment
Fix issues first] Fail2 --> Block Fail3 --> Block Fail4 --> Block style Fail1 fill:#7f1d1d,stroke:#ef4444 style Fail2 fill:#7f1d1d,stroke:#ef4444 style Fail3 fill:#7f1d1d,stroke:#ef4444 style Fail4 fill:#7f1d1d,stroke:#ef4444 style AllGates fill:#064e3b,stroke:#10b981
Code Quality} Gate1 --> CheckLint[Check Linting
ESLint, Prettier] Gate1 --> CheckComplexity[Check Complexity
Cyclomatic complexity
< 10 per function] Gate1 --> CheckDuplication[Check Duplication
Code duplication < 3%] CheckLint --> LintScore{Pass?} CheckComplexity --> ComplexScore{Pass?} CheckDuplication --> DupScore{Pass?} LintScore -->|No| Fail1[❌ Gate 1 Failed] ComplexScore -->|No| Fail1 DupScore -->|No| Fail1 LintScore -->|Yes| Gate2{Quality Gate 2:
Testing} ComplexScore -->|Yes| Gate2 DupScore -->|Yes| Gate2 Gate2 --> CheckCoverage[Check Coverage
Line coverage >= 80%
Branch coverage >= 75%] Gate2 --> CheckTests[All Tests Pass
Unit + Integration] Gate2 --> CheckPerf[Performance Tests
Response time < baseline] CheckCoverage --> CovScore{Pass?} CheckTests --> TestScore{Pass?} CheckPerf --> PerfScore{Pass?} CovScore -->|No| Fail2[❌ Gate 2 Failed] TestScore -->|No| Fail2 PerfScore -->|No| Fail2 CovScore -->|Yes| Gate3{Quality Gate 3:
Security} TestScore -->|Yes| Gate3 PerfScore -->|Yes| Gate3 Gate3 --> CheckVuln[Scan Vulnerabilities
No high/critical CVEs] Gate3 --> CheckSecrets[Check for Secrets
No hardcoded credentials] Gate3 --> CheckDeps[Dependency Check
All deps up-to-date] CheckVuln --> VulnScore{Pass?} CheckSecrets --> SecretScore{Pass?} CheckDeps --> DepScore{Pass?} VulnScore -->|No| Fail3[❌ Gate 3 Failed] SecretScore -->|No| Fail3 DepScore -->|No| Fail3 VulnScore -->|Yes| Gate4{Quality Gate 4:
Production Readiness} SecretScore -->|Yes| Gate4 DepScore -->|Yes| Gate4 Gate4 --> CheckHealth[Health Checks
Liveness + Readiness] Gate4 --> CheckResources[Resource Limits
CPU + Memory defined] Gate4 --> CheckDocs[Documentation
README + API docs] CheckHealth --> HealthScore{Pass?} CheckResources --> ResScore{Pass?} CheckDocs --> DocScore{Pass?} HealthScore -->|No| Fail4[❌ Gate 4 Failed] ResScore -->|No| Fail4 DocScore -->|No| Fail4 HealthScore -->|Yes| AllGates[✅ All Quality Gates Passed!
Ready for deployment] ResScore -->|Yes| AllGates DocScore -->|Yes| AllGates Fail1 --> Block[Block deployment
Fix issues first] Fail2 --> Block Fail3 --> Block Fail4 --> Block style Fail1 fill:#7f1d1d,stroke:#ef4444 style Fail2 fill:#7f1d1d,stroke:#ef4444 style Fail3 fill:#7f1d1d,stroke:#ef4444 style Fail4 fill:#7f1d1d,stroke:#ef4444 style AllGates fill:#064e3b,stroke:#10b981
Part 5: GitLab CI/CD Example
.gitlab-ci.yml Configuration
# .gitlab-ci.yml
stages:
- lint
- test
- build
- security
- deploy-staging
- deploy-production
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
# Template for Docker jobs
.docker-login: &docker-login
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
# Stage 1: Linting
lint:code:
stage: lint
image: node:18
script:
- npm ci
- npm run lint
- npm run format:check
cache:
paths:
- node_modules/
# Stage 2: Testing
test:unit:
stage: test
image: node:18
script:
- npm ci
- npm test -- --coverage
- |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% is below threshold"
exit 1
fi
coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
test:integration:
stage: test
image: node:18
services:
- name: postgres:15
alias: postgres
- name: redis:7
alias: redis
variables:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/test
REDIS_URL: redis://redis:6379
script:
- npm ci
- npm run test:integration
# Stage 3: Build
build:image:
stage: build
image: docker:24
services:
- docker:24-dind
<<: *docker-login
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
- docker tag $IMAGE_TAG $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
only:
- main
- develop
# Stage 4: Security Scanning
security:scan:
stage: security
image: aquasec/trivy:latest
script:
- trivy image --severity HIGH,CRITICAL --exit-code 1 $IMAGE_TAG
allow_failure: true
security:sast:
stage: security
image: node:18
script:
- npm audit --audit-level=high
- npx snyk test --severity-threshold=high
allow_failure: true
# Stage 5: Deploy to Staging
deploy:staging:
stage: deploy-staging
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster k8s --server="$K8S_SERVER"
- kubectl config set-credentials admin --token="$K8S_TOKEN"
- kubectl config set-context default --cluster=k8s --user=admin
- kubectl config use-context default
- |
kubectl set image deployment/myapp \
myapp=$IMAGE_TAG \
-n staging
- kubectl rollout status deployment/myapp -n staging --timeout=5m
- kubectl get pods -n staging
environment:
name: staging
url: https://staging.example.com
only:
- main
# Stage 6: Deploy to Production
deploy:production:
stage: deploy-production
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster k8s --server="$K8S_SERVER"
- kubectl config set-credentials admin --token="$K8S_TOKEN"
- kubectl config set-context default --cluster=k8s --user=admin
- kubectl config use-context default
- |
kubectl set image deployment/myapp \
myapp=$IMAGE_TAG \
-n production
- kubectl rollout status deployment/myapp -n production --timeout=10m
- |
# Check pod health
READY=$(kubectl get deployment myapp -n production -o jsonpath='{.status.readyReplicas}')
DESIRED=$(kubectl get deployment myapp -n production -o jsonpath='{.spec.replicas}')
if [ "$READY" != "$DESIRED" ]; then
echo "Deployment unhealthy: $READY/$DESIRED pods ready"
kubectl rollout undo deployment/myapp -n production
exit 1
fi
environment:
name: production
url: https://example.com
when: manual # Require manual approval
only:
- main
Part 6: Pipeline Best Practices
Pipeline Optimization
Fast Feedback Loop:
Fail Fast Principle:
├─ Run fastest checks first (linting: 30s)
├─ Then unit tests (2-3 min)
├─ Then build (5-10 min)
└─ Finally integration tests (10-15 min)
Don't run slow tests if fast ones fail!
Caching Strategy:
# Cache dependencies
cache:
paths:
- node_modules/
- .npm/
- vendor/
# Use Docker layer caching
- docker build --cache-from $IMAGE_TAG .
Parallel Execution:
# Run independent jobs in parallel
test:unit:
# Runs in parallel
test:integration:
# Runs in parallel
build:frontend:
# Runs in parallel
build:backend:
# Runs in parallel
Conclusion
A well-designed CI/CD pipeline:
- Automates repetitive tasks: Testing, building, deploying
- Provides fast feedback: Catch issues early
- Ensures quality: Quality gates prevent bad code from shipping
- Enables confidence: Deploy frequently with less risk
- Improves productivity: Developers focus on features, not deployments
Key components:
- Automated testing (unit, integration, e2e)
- Quality gates (coverage, security, performance)
- Automated deployments (staging → production)
- Monitoring and rollback mechanisms
- Fast feedback loops
The visual diagrams in this guide show how code flows from commit to production, making the CI/CD process transparent and understandable.
Further Reading
- GitHub Actions Documentation
- GitLab CI/CD Documentation
- The Twelve-Factor App
- Continuous Delivery Book - Jez Humble
Automate everything, deploy with confidence!