Skip to content

mayur2410-tech/production-ready-docker-cicd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Production-Ready Docker CI/CD Pipeline

GitHub Workflow Status Docker Pulls GitHub repo size GitHub stars

Docker AWS GitHub Actions Node.js

Automated Deployment Pipeline for Laundry Buddy Backend

GitHub Actions Docker DockerHub AWS EC2 Node.js


A complete CI/CD pipeline using GitHub Actions, Docker, DockerHub, and AWS EC2 for automated deployments!

Features β€’ Architecture β€’ Setup β€’ Tech Stack


πŸ“Œ Wrokflow Diagram

diagram-export-1-29-2026-11_38_23-AM


πŸ“Œ Project Overview

This project demonstrates a production-style CI/CD pipeline for the Laundry Buddy backend. Whenever code is pushed to the main branch, it automatically runs tests, builds a Docker image, pushes to DockerHub, and deploys to AWS EC2 - all without manual intervention.

πŸ’‘ The Problem This Solves

Traditional Deployment ❌ This Solution βœ…
Manual server SSH and deployment Fully automated via GitHub Actions
"It works on my machine" syndrome Consistent Docker images everywhere
Unreliable deployments Tested code only reaches production
No version control for deployments Every image tagged with commit SHA
Manual testing before deploy Automated testing in CI pipeline

🎯 Why This CI/CD Pipeline?

Manual deployment is slow and risky. This pipeline ensures:

  • βœ… Consistent deployments (same Docker image everywhere)
  • βœ… Automation (no manual server work after setup)
  • βœ… Reliability (only tested code deploys)
  • βœ… Scalability (works for any server that can pull Docker images)
  • βœ… Version control (every image tagged with commit SHA)

πŸ—οΈ Architecture Flow

graph TD
    A[πŸ‘¨β€πŸ’» Developer Push to main] -->|Triggers CI/CD| B[βš™οΈ GitHub Actions]
    B -->|Stage 1| C[πŸ§ͺ Run Tests]
    C -->|Stage 2| D[🧹 Lint Code]
    D -->|Stage 3| E[πŸ” Security Audit]
    E -->|Stage 4| F[🐳 Build Docker Image]
    F -->|Push to Registry| G[πŸ“¦ DockerHub]
    G -->|Stage 5| H[☁️ Deploy to EC2]
    H -->|SSH & Pull| I[πŸš€ Live Application]
    
    style A fill:#e1f5ff
    style B fill:#fff4e1
    style C fill:#e8f5e9
    style D fill:#e8f5e9
    style E fill:#fff3e0
    style F fill:#e3f2fd
    style G fill:#f3e5f5
    style H fill:#fff8e1
    style I fill:#c8e6c9
Loading

Complete Pipeline Flow:

  1. Developer pushes code to main branch
  2. GitHub Actions triggers automatically
  3. CI Stage - Run tests, lint, security audit
  4. Build Stage - Create Docker image with two tags (latest + commit SHA)
  5. Push Stage - Upload image to DockerHub registry
  6. Deploy Stage - SSH to EC2, pull latest image, restart container
  7. Application is live with zero downtime! πŸŽ‰

🧰 Tech Stack

Technology Purpose Version
Node.js Backend Runtime 22+
Docker Containerization Latest
DockerHub Image Registry -
GitHub Actions CI/CD Automation -
AWS EC2 Production Server Ubuntu 24
ESLint Code Quality Latest
npm audit Security Scanning Built-in

βš™οΈ CI/CD Pipeline Stages

Complete Automation Process

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STAGE 1: Testing (CI)                                   β”‚
β”‚ β€’ Checkout code                                         β”‚
β”‚ β€’ Setup Node.js 22                                      β”‚
β”‚ β€’ Cache dependencies                                    β”‚
β”‚ β€’ Install dependencies (npm ci)                         β”‚
β”‚ β€’ Run automated tests (npm test)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ βœ… Tests Pass
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STAGE 2: Linting (CI)                                   β”‚
β”‚ β€’ Run ESLint checks                                     β”‚
β”‚ β€’ Validate code quality                                 β”‚
β”‚ β€’ Ensure coding standards                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ βœ… Lint Pass
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STAGE 3: Security Scan (CI)                             β”‚
β”‚ β€’ Run npm audit                                         β”‚
β”‚ β€’ Check for high-severity vulnerabilities               β”‚
β”‚ β€’ Validate dependencies                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ βœ… Security Pass
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STAGE 4: Build & Push Docker Image                      β”‚
β”‚ β€’ Login to DockerHub                                    β”‚
β”‚ β€’ Build Docker image                                    β”‚
β”‚ β€’ Tag with 'latest' and commit SHA                      β”‚
β”‚ β€’ Push to DockerHub registry                            β”‚
β”‚   β†’ mayur2410/laundrybuddy-backend:latest               β”‚
β”‚   β†’ mayur2410/laundrybuddy-backend:{commit-sha}         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚ βœ… Image Built & Pushed
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ STAGE 5: Deploy to EC2 (CD)                             β”‚
β”‚ β€’ SSH into EC2 instance                                 β”‚
β”‚ β€’ Pull latest Docker image                              β”‚
β”‚ β€’ Stop old container                                    β”‚
β”‚ β€’ Start new container                                   β”‚
β”‚ β€’ Verify deployment                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚
                βœ… LIVE ON EC2!
                Total Time: ~5-7 minutes

πŸ“‚ Project Structure

production-ready-docker-cicd/
β”‚
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── ci-cd.yaml          # Complete CI/CD workflow
β”‚
β”œβ”€β”€ Backend/
β”‚   β”œβ”€β”€ Dockerfile              # Docker image configuration
β”‚   β”œβ”€β”€ package.json            # Node.js dependencies
β”‚   β”œβ”€β”€ package-lock.json       # Lock file for dependencies
β”‚   β”œβ”€β”€ server.js               # Application entry point
β”‚   β”œβ”€β”€ config/                 # Configuration files
β”‚   β”œβ”€β”€ controllers/            # Route controllers
β”‚   β”œβ”€β”€ models/                 # Database models
β”‚   β”œβ”€β”€ routes/                 # API routes
β”‚   └── middleware/             # Custom middleware
β”‚
└── README.md                   # Project documentation (you're here!)

πŸš€ Setup Guide

Prerequisites

  • βœ… AWS Account with EC2 instance running
  • βœ… DockerHub account
  • βœ… GitHub repository
  • βœ… SSH key pair for EC2 access
  • βœ… Basic knowledge of Docker, Git & AWS

1️⃣ EC2 Server Setup

SSH into your EC2 instance and install Docker:

# SSH into your EC2 instance
ssh -i your-key.pem ubuntu@your-ec2-public-ip

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group (no sudo needed)
sudo usermod -aG docker $USER

# Enable and start Docker
sudo systemctl enable docker
sudo systemctl start docker

# Verify installation
docker --version

Create deployment directory and environment file:

# Create deployment directory
mkdir -p ~/laundrybuddy-backend
cd ~/laundrybuddy-backend

# Create environment file
nano .env

Add your environment variables to .env:

PORT=3000
MONGODB_URL=mongodb+srv://your-connection-string
JWT_SECRET=your-secret-key-here
TWILIO_ACCOUNT_SID=your-twilio-sid
TWILIO_AUTH_TOKEN=your-twilio-token
EMAIL_USER=your-email@gmail.com
EMAIL_PASSWORD=your-email-password
FRONTEND_URL=https://your-frontend-url.com

⚠️ Important: Never commit .env to GitHub!

Create deployment script:

nano deploy.sh

Add this content:

#!/bin/bash

# Pull latest image from DockerHub
docker pull mayur2410/laundrybuddy-backend:latest

# Stop and remove old container
docker stop laundrybuddy-backend || true
docker rm laundrybuddy-backend || true

# Run new container
docker run -d \
  --name laundrybuddy-backend \
  --restart unless-stopped \
  -p 3000:3000 \
  --env-file .env \
  mayur2410/laundrybuddy-backend:latest

# Show logs
docker logs -f laundrybuddy-backend

Make it executable:

chmod +x deploy.sh

Test manual deployment:

./deploy.sh

If you see the server running β†’ EC2 setup is complete! πŸš€


2️⃣ GitHub Secrets Configuration

Navigate to: Repository β†’ Settings β†’ Secrets and variables β†’ Actions β†’ New repository secret

🐳 DockerHub Secrets

Secret Name Value How to Get
DOCKERHUB_USERNAME mayur2410 Your DockerHub username
DOCKERHUB_TOKEN dckr_pat_xxxxx... DockerHub β†’ Account Settings β†’ Security β†’ New Access Token

☁️ AWS EC2 Secrets

Secret Name Value How to Get
EC2_HOST ec2-xx-xx-xx-xx.compute.amazonaws.com EC2 Public IPv4 DNS or IP
EC2_USERNAME ubuntu Default user (ubuntu for Ubuntu AMI)
EC2_SSH_KEY -----BEGIN RSA PRIVATE KEY-----... Content of your .pem file

How to get EC2_SSH_KEY:

# On your local machine
cat your-key.pem

# Copy entire content including:
# -----BEGIN RSA PRIVATE KEY-----
# ... (all lines)
# -----END RSA PRIVATE KEY-----

3️⃣ Docker Configuration

Create Dockerfile in your Backend/ directory:

FROM node:22-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

CMD ["node", "server.js"]

What This Does:

  • βœ… Uses Node.js 22 Alpine (lightweight base image)
  • βœ… Sets working directory to /app
  • βœ… Copies dependency files first (layer caching optimization)
  • βœ… Installs dependencies
  • βœ… Copies application code
  • βœ… Exposes port 3000
  • βœ… Starts server with node server.js

4️⃣ GitHub Actions Workflow

Create .github/workflows/ci-cd.yaml:

name: CI/CD Pipeline

on:
  push:
    branches:
      - main

jobs:
  test:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: Backend
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: Backend/package-lock.json
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test

  lint:
    needs: test
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: Backend
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '22'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run ESLint
        run: npm run lint

  security:
    needs: [test, lint]
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: Backend
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '22'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run security audit
        run: npm audit --audit-level=high

  build_and_push:
    needs: [test, lint, security]
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      
      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: ./Backend
          push: true
          tags: |
            mayur2410/laundrybuddy-backend:latest
            mayur2410/laundrybuddy-backend:${{ github.sha }}

  deploy:
    needs: build_and_push
    runs-on: ubuntu-latest
    
    steps:
      - name: Deploy to EC2
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ${{ secrets.EC2_USERNAME }}
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            cd ~/laundrybuddy-backend
            docker pull mayur2410/laundrybuddy-backend:latest
            docker stop laundrybuddy-backend || true
            docker rm laundrybuddy-backend || true
            docker run -d \
              --name laundrybuddy-backend \
              --restart unless-stopped \
              -p 3000:3000 \
              --env-file .env \
              mayur2410/laundrybuddy-backend:latest
            docker logs --tail 50 laundrybuddy-backend

5️⃣ Test Your Deployment

# Make a change to your code
echo "// CI/CD pipeline test" >> Backend/server.js

# Commit and push
git add .
git commit -m "Test CI/CD pipeline"
git push origin main

# Watch GitHub Actions run automatically
# Visit: https://github.com/your-username/your-repo/actions

βœ… Key Features

Feature Benefit
πŸ§ͺ Automated Testing Every push runs full test suite
🧹 Code Quality Checks ESLint ensures clean code
πŸ” Security Scanning npm audit catches vulnerabilities
🐳 Docker Containerization Consistent environment everywhere
πŸ“¦ Image Registry DockerHub stores all versions
🏷️ Version Tagging Latest + commit SHA for rollbacks
⚑ Zero Downtime Seamless container replacement
πŸ”„ Automatic Deployment Push to main = live in 5-7 minutes

🧰 Useful Commands

πŸ“Š On EC2 Instance

# View running containers
docker ps

# View all containers (including stopped)
docker ps -a

# View backend logs
docker logs laundrybuddy-backend

# Follow logs in real-time
docker logs -f laundrybuddy-backend

# View last 100 lines
docker logs --tail 100 laundrybuddy-backend

# Check container stats (CPU, Memory)
docker stats laundrybuddy-backend

# Restart container
docker restart laundrybuddy-backend

# Stop container
docker stop laundrybuddy-backend

# Remove container
docker rm laundrybuddy-backend

# View Docker images
docker images

# Remove unused images (cleanup)
docker image prune -af

# Remove all stopped containers
docker container prune -f

πŸ”§ Manual Deployment

# If CI/CD fails, deploy manually:
cd ~/laundrybuddy-backend
./deploy.sh

πŸ”„ Rollback to Previous Version

# Use specific commit SHA tag
docker pull mayur2410/laundrybuddy-backend:f6dcb3096fd2532f896bb438bc3172a096349886

docker stop laundrybuddy-backend
docker rm laundrybuddy-backend

docker run -d \
  --name laundrybuddy-backend \
  --restart unless-stopped \
  -p 3000:3000 \
  --env-file .env \
  mayur2410/laundrybuddy-backend:f6dcb3096fd2532f896bb438bc3172a096349886

πŸ› Troubleshooting

Common Issues & Solutions

❌ Pipeline Failing at Test Stage
# Run tests locally
cd Backend/
npm install
npm test

# Check Node.js version
node --version  # Should be v22
❌ Pipeline Failing at Lint Stage
# Run lint locally
npm run lint

# Auto-fix issues
npx eslint . --fix
❌ Pipeline Failing at Security Stage
# Run audit locally
npm audit

# Fix vulnerabilities automatically
npm audit fix

# Force fix (may break things)
npm audit fix --force
❌ Docker Build Failing
# Build locally to debug
cd Backend/
docker build -t test-build .

# Check for syntax errors in Dockerfile
docker build --no-cache -t test-build .
❌ Cannot Push to DockerHub

Check:

  • βœ… DOCKERHUB_USERNAME is correct
  • βœ… DOCKERHUB_TOKEN is valid (regenerate if needed)
  • βœ… Token has Read & Write permissions
❌ SSH Connection to EC2 Failing

Check:

  • βœ… EC2_HOST is correct (public IP or DNS)
  • βœ… EC2_USERNAME is correct (ubuntu or ec2-user)
  • βœ… EC2_SSH_KEY includes entire .pem file content
  • βœ… EC2 Security Group allows SSH (port 22) from GitHub IP ranges
  • βœ… EC2 instance is running
❌ Container Not Starting on EC2
# Check Docker logs
docker logs laundrybuddy-backend

# Check if port 3000 is already in use
sudo netstat -tulpn | grep 3000

# Kill process using port 3000
sudo kill -9 <PID>

# Check disk space
df -h

# Check memory
free -m

# Restart Docker service
sudo systemctl restart docker
❌ Application Running but Not Accessible

Check:

  • βœ… EC2 Security Group allows inbound traffic on port 3000
  • βœ… MongoDB connection string is correct in .env
  • βœ… All environment variables are set correctly
# Test locally on EC2
curl http://localhost:3000

# Should return: "Server is ready on EC2"

πŸ“Š Pipeline Metrics

Stage Average Time Can Fail?
Test 45-60 sec βœ… Yes
Lint 20-30 sec βœ… Yes
Security 30-40 sec βœ… Yes
Build & Push 2-3 min βœ… Yes
Deploy 30-45 sec βœ… Yes
Total ~5-7 min

πŸ” Security Best Practices

This project implements production-grade security:

Security Measure Implementation
πŸ”‘ Environment Variables Stored in GitHub Secrets (never in code)
πŸ”’ SSH Key Storage Encrypted in GitHub Secrets
πŸ›‘οΈ DockerHub Token Access token instead of password
πŸ” Security Audits npm audit runs on every build
🐧 Alpine Linux Smaller attack surface
πŸ”„ Container Restart Policy Ensures uptime and reliability

πŸŽ“ What You'll Learn

By working with this project, you'll understand:

  • βœ… How to build a complete CI/CD pipeline from scratch
  • βœ… How to containerize Node.js applications with Docker
  • βœ… How to write multi-stage GitHub Actions workflows
  • βœ… How to push images to DockerHub registry
  • βœ… How to deploy to AWS EC2 securely via SSH
  • βœ… How to implement automated testing in CI/CD
  • βœ… How to handle secrets and environment variables
  • βœ… DevOps best practices for production deployments

πŸš€ Future Improvements

  • Health Checks β†’ Automatic rollback on deployment failure
  • Slack/Discord Notifications β†’ Build status alerts
  • Nginx Reverse Proxy β†’ HTTPS with SSL certificates
  • Staging Environment β†’ Test before production deployment
  • Blue-Green Deployment β†’ Zero-downtime updates
  • Database Backups β†’ Automated MongoDB backups
  • Monitoring β†’ Prometheus + Grafana dashboards
  • Log Aggregation β†’ ELK Stack (Elasticsearch, Logstash, Kibana)
  • Multi-Region Deployment β†’ High availability setup
  • Auto-Scaling β†’ Based on traffic patterns

πŸ“š Resources & Documentation


πŸ‘¨β€πŸ’» Author

Mayur
πŸŽ“ B.Tech Student | DevOps Enthusiast
🐳 Docker β€’ βš™οΈ GitHub Actions β€’ ☁️ AWS β€’ πŸ§ͺ CI/CD

GitHub: @mayur2410-tech


πŸ“ License

This project is licensed under the ISC License.


🀝 Contributing

Contributions are welcome! Here's how you can help:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

⭐ Show Your Support

If this project helped you understand CI/CD pipelines, please give it a star! ⭐


Made with ❀️ for learning DevOps

About

πŸš€ Complete CI/CD pipeline: GitHub Actions + Docker + AWS EC2 | Auto-deploy with testing, linting & security checks πŸ³βš™οΈβ˜οΈ

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages