Tech With Htunn
  • Blog Content
  • 🤖Artificial Intelligence
    • 🧠Building an Intelligent Agent with Local LLMs and Azure OpenAI
    • 📊Revolutionizing IoT Monitoring: My Personal Journey with LLM-Powered Observability
  • 📘Core Concepts
    • 🔄Understanding DevSecOps
    • ⬅️Shifting Left in DevSecOps
    • 📦Understanding Containerization
    • ⚙️What is Site Reliability Engineering?
    • ⏱️Understanding Toil in SRE
    • 🔐What is Identity and Access Management?
    • 📊Microsoft Graph API: An Overview
    • 🔄Understanding Identity Brokers
  • 🔎Security Testing
    • 🔍SAST vs DAST: Understanding the Differences
    • 🧩Software Composition Analysis (SCA)
    • 📋Software Bill of Materials (SBOM)
    • 🧪Dependency Scanning in DevSecOps
    • 🐳Container Scanning in DevSecOps
  • 🔄CI/CD Pipeline
    • 🔁My Journey with Continuous Integration in DevOps
    • 🚀My Journey with Continuous Delivery and Deployment in DevOps
  • 🧮Fundamentals
    • 💾What is Data Engineering?
    • 🔄Understanding DataOps
    • 👷The Role of a Cloud Architect
    • 🏛️Cloud Native Architecture
    • 💻Cloud Native Applications
  • 🏛️Architecture & Patterns
    • 🏅Medallion Architecture in Data Engineering
    • 🔄ETL vs ELT Pipeline: Understanding the Differences
  • 🔒Authentication & Authorization
    • 🔑OAuth 2.0 vs OIDC: Key Differences
    • 🔐Understanding PKCE in OAuth 2.0
    • 🔄Service Provider vs Identity Provider Initiated SAML Flows
  • 📋Provisioning Standards
    • 📊SCIM in Identity and Access Management
    • 📡Understanding SCIM Streaming
  • 🏗️Design Patterns
    • ⚡Event-Driven Architecture
    • 🔒Web Application Firewalls
  • 📊Reliability Metrics
    • 💰Error Budgets in SRE
    • 📏SLA vs SLO vs SLI: Understanding the Differences
    • ⏱️Mean Time to Recovery (MTTR)
Powered by GitBook
On this page
  • Continuous Delivery vs. Deployment: What I've Learned
  • Continuous Delivery: Trust But Verify
  • Continuous Deployment: The Ultimate Automation
  • My Real-World GitLab CI/CD Implementation
  • Step 1: Creating Our Pipeline Configuration
  • Step 2: Setting Up Our Build and Test Jobs
  • Step 3: Adding Quality Gates
  • Step 4: Implementing Continuous Delivery First
  • Step 5: Graduating to Continuous Deployment
  • Step 6: Adding Rollback Capability
  • The Real Impact on My Team's Work
  • Personal Lessons I've Learned Along the Way
  • Final Thoughts
  1. CI/CD Pipeline

My Journey with Continuous Delivery and Deployment in DevOps

When I first started as a developer six years ago, deploying code was an event. We'd schedule releases weeks in advance, pull all-nighters, and pray nothing would break. Today, my team deploys multiple times a day without breaking a sweat—all thanks to Continuous Delivery and Deployment practices. Let me share how this transformation changed my development life forever.

Continuous Delivery vs. Deployment: What I've Learned

Throughout my career, I've witnessed the evolution from manual deployments to fully automated pipelines. Let me explain the difference between these two practices based on my experience:

Continuous Delivery: Trust But Verify

In my first DevOps role, we implemented Continuous Delivery (CD)—a practice where every code change is automatically built, tested, and prepared for release to production, but with a crucial manual approval step at the end.

I remember when our team first set this up. Our CTO was nervous about fully automated deployments, so we compromised with a system where code was always ready to ship, but someone (usually me!) had to click the "Deploy" button. This gave us confidence while maintaining control.

Continuous Deployment: The Ultimate Automation

Three years ago, we took the leap to Continuous Deployment—where every change that passes our automated tests is automatically released to production without human intervention.

I was skeptical at first: "What if something breaks?" But after setting up comprehensive automated testing and monitoring, I became a believer. Now, instead of spending my Thursdays deploying code, I'm building new features—while our pipeline handles over 20 deployments daily.

My Real-World GitLab CI/CD Implementation

After trying several CI/CD tools, my team settled on GitLab for its integrated approach. Here's how I've set up our pipeline for a Node.js application, with lessons learned along the way:

Step 1: Creating Our Pipeline Configuration

I added a .gitlab-ci.yml file to our repository's root directory. This was the foundation of our automation:

stages:
  - build
  - test
  - quality
  - deploy_staging
  - deploy_production

variables:
  NODE_ENV: 'production'

cache:
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - node_modules/

Pro tip I learned the hard way: Setting the cache key to ${CI_COMMIT_REF_SLUG} ensures each branch gets its own cache, which prevents weird dependency issues between branches.

Step 2: Setting Up Our Build and Test Jobs

build:
  stage: build
  script:
    - echo "Installing dependencies..."
    - npm ci
    - echo "Building application..."
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

test:
  stage: test
  script:
    - echo "Running tests..."
    - npm test
  coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/

A lesson from the trenches: I switched from npm install to npm ci after our builds kept breaking due to inconsistent package versions. The ci command guarantees a clean, reproducible build every time.

Step 3: Adding Quality Gates

After a particularly painful incident where we deployed code with memory leaks to production, I added quality gates:

lint:
  stage: quality
  script:
    - npm run lint
    
security_scan:
  stage: quality
  script:
    - npm audit
  allow_failure: true

I set allow_failure: true on the security scan because we wanted to see vulnerabilities without blocking the pipeline while we worked through our backlog of fixes.

Step 4: Implementing Continuous Delivery First

We started with Continuous Delivery, requiring manual approval for production:

deploy_staging:
  stage: deploy_staging
  script:
    - echo "Deploying to staging..."
    - ./deploy.sh staging
  environment:
    name: staging
    url: https://staging.mycompany.com
  only:
    - master

deploy_production:
  stage: deploy_production
  script:
    - echo "Deploying to production..."
    - ./deploy.sh production
  environment:
    name: production
    url: https://mycompany.com
  when: manual
  only:
    - master

That when: manual line was our safety net—requiring someone to review the staging deployment before approving production.

Step 5: Graduating to Continuous Deployment

After six months with zero major incidents, I convinced my team to remove the manual approval step:

deploy_production:
  stage: deploy_production
  script:
    - echo "Deploying to production..."
    - ./deploy.sh production
  environment:
    name: production
    url: https://mycompany.com
  only:
    - master

I still remember removing that when: manual line—it felt like removing training wheels!

Step 6: Adding Rollback Capability

After one particularly bad deployment (which happened right before a company demo!), I added this rollback job:

rollback:
  stage: deploy_production
  script:
    - echo "Rolling back to previous version..."
    - ./rollback.sh
  environment:
    name: production
  when: manual
  only:
    - master

Being able to click a button and immediately revert to the previous working version saved me more than once during late-night incidents.

The Real Impact on My Team's Work

The journey to Continuous Deployment wasn't always smooth, but the results have been incredible:

  1. We deploy 20x more frequently—from once every two weeks to multiple times daily

  2. Our lead time dropped from days to minutes—code reaches users on the same day it's written

  3. Deployment stress disappeared—my team no longer dreads releases

  4. Our weekend support calls decreased by 80%—better testing means fewer production issues

  5. Developer happiness increased—measured by our quarterly team surveys

Personal Lessons I've Learned Along the Way

If you're considering implementing CD/CD, here are my hard-earned insights:

  1. Start with thorough automated testing—without this foundation, you're building on sand

  2. Implement feature flags—they've saved my team countless times by allowing us to disable problematic features without rolling back entire deployments

  3. Monitor everything—we set up dashboards that immediately alert us to any anomalies after deployment

  4. Take small steps—we didn't jump straight to Continuous Deployment; we built confidence with Continuous Delivery first

  5. Culture matters as much as tools—I had to help my team embrace the mindset that fast, small releases are actually safer than big batch deployments

Final Thoughts

When people ask me what changed my development career the most, I always point to embracing Continuous Delivery and Deployment. These practices transformed not just how we release software, but how we think about building it.

The ability to get code into users' hands quickly, safely, and repeatedly isn't just a technical achievement—it's the foundation of modern software development that brings real business value. And once you experience the confidence of a solid CI/CD pipeline, you'll never want to go back to the old ways.

Now when my team merges a critical bug fix, we don't schedule a release meeting—we just wait a few minutes and tell the customer "it's already live."

PreviousMy Journey with Continuous Integration in DevOpsNextWhat is Data Engineering?

Last updated 2 days ago

🔄
🚀