Automating CI/CD for My App with Jenkins, Docker, and GitHub Webhooks πŸš€

Atharv KarpeAtharv Karpe
5 min read

πŸ“Œ Introduction

In my journey as a DevOps enthusiast, I recently deep-dived into Jenkins and successfully set up a complete CI/CD pipeline for a banking application. I had already learned Linux, shell scripting, Docker, Docker Compose, and even deployed my app on an AWS EC2 server using distroless images. This time, I took it to the next level by learning CI/CD with Jenkins, automating deployments, integrating with GitHub, and setting up email alerts for pipeline status.

In this blog, I’ll walk you through what I learned, how I did it, and why these practices are essential in the DevOps world.


πŸš€ What is CI/CD and Why Do We Use It?

CI/CD stands for:

  • CI (Continuous Integration): Automatically building and testing code every time a developer commits changes to version control (e.g., GitHub).

  • CD (Continuous Deployment/Delivery): Automatically deploying code to production or staging environments after passing tests.

This process reduces manual intervention, speeds up software delivery, and ensures fewer bugs in production.

With tools like Jenkins, we can automate the entire CI/CD pipeline from cloning the repo to deploying the app seamlessly.


βš™οΈ Prerequisites for Jenkins CI/CD

To set up a Jenkins-based CI/CD pipeline, I installed the following tools:

  • βœ… Java (required for Jenkins)

  • βœ… Jenkins (open-source automation server)

  • βœ… Docker (to containerize the app)

  • βœ… Docker Compose (to deploy multi-container apps easily)


🧱 Types of Jenkins Pipelines

Jenkins supports two main pipeline types:

1. Declarative Pipeline (the one I used)

  • Simpler and more structured.

  • Uses a predefined syntax with pipeline {} block.

2. Scripted Pipeline

  • Uses full Groovy scripting.

  • Offers more control but requires more code.

βœ… For my project, I chose Declarative Pipeline due to its clean and beginner-friendly syntax.


πŸ“œ Jenkins Pipeline Structure (Groovy Syntax)

Here’s the basic structure of a declarative pipeline:

pipeline {
    agent any

    stages {
        stage('Code') {
            steps {
                echo 'Cloning the code...'
            }
        }
        stage('Build') {
            steps {
                echo 'Building the app...'
            }
        }
        stage('Test') {
            steps {
                echo 'Running tests...'
            }
        }
        stage('Deploy') {
            steps {
                echo 'Deploying the app...'
            }
        }
    }
}

πŸ’‘ What is an Agent in Jenkins?

Agent defines where the Jenkins pipeline runs. It can be:

  • agent any: Run on any available Jenkins agent.

  • agent { label "label_name" }: Run on a specific node.

πŸ‘‰ My Setup:

I created a dedicated agent node on an AWS EC2 server to deploy my app. This offloads deployment from the Jenkins master node and allows me to scale deployments across multiple servers.

Benefit: Distributing workload and separating Jenkins from application hosting.


πŸ”„ Jenkins Pipeline Stages I Created

Here are the stages I implemented in my Jenkins pipeline:

  1. Clone – Pulled code from GitHub repository.

  2. Scan – Used Trivy to perform vulnerability scanning (DevSecOps).

  3. Build – Built a Docker image using a distroless Dockerfile.

  4. Test – Placeholder for testing (can be extended with real test cases).

  5. Push – Logged into Docker Hub and pushed the image securely using Jenkins credentials.

  6. Deploy – Pulled the image and deployed it using Docker Compose.

  7. Clean – Cleaned up unused Docker images and containers to save disk space.


πŸ” Trivy & DevSecOps: Security First

In the Scan stage, I used Trivy an open-source vulnerability scanner. It scans OS packages, dependencies, and container images.

This integrates DevSecOps into the pipeline, ensuring security is not an afterthought but part of the development process.


🐳 Docker Distroless Image for Smaller Attack Surface

I created a distroless Docker image, which contains only the necessary application dependencies no shell, no package manager.

βœ… Benefits:

  • Smaller image size

  • Better security

  • Faster startup time


πŸ™ Pushing Images to Docker Hub Securely

Instead of hardcoding Docker Hub credentials in my pipeline, I stored them in Jenkins Credentials and accessed them like this:

withCredentials([usernamePassword(credentialsId: 'DockerHubCreds', usernameVariable: 'dockerHubUser', passwordVariable: 'dockerHubPass')]) {
    sh "docker login -u $dockerHubUser -p $dockerHubPass"
    // push image
}

This keeps secrets safe and follows DevOps best practices.


🧩 Docker Compose for Deployment

In the Deploy stage, I used Docker Compose to run multi-container services (like backend + DB).

Example command:

docker compose up -d --build bankapp

Docker Compose makes it easy to define and run multi-container Docker apps using a simple YAML file.


🧹 Cleaning Up: Avoid Disk Bloat

To avoid Jenkins agents running out of disk space, I added a final Clean stage:

docker system prune -a --force

This removes unused images, containers, and networks.


πŸ”” GitHub Webhook Integration

I connected my GitHub repo to Jenkins using a Webhook, so every time I push code, Jenkins automatically triggers the pipeline.

βœ… No need to manually trigger builds CI in action!


πŸ“§ Email Notifications with SMTP

I configured an SMTP server in Jenkins and used the emailext plugin to send email alerts:

  • If the pipeline is successful or fails, I get an email.

Example from my pipeline:

post {
    success {
        emailext(
            to: 'email',
            subject: 'Pipeline is successful',
            body: 'Your banking app pipeline ran successfully!'
        )
    }
    failure {
        emailext(
            to: 'email',
            subject: 'Pipeline Failed',
            body: 'Please check Jenkins logs for errors.'
        )
    }
}

βœ… Final Thoughts: A Robust CI/CD Pipeline

By combining everything above, I’ve created a production-grade CI/CD pipeline that:

  • Automatically builds, tests, and deploys my app

  • Scans for vulnerabilities

  • Pushes images securely to Docker Hub

  • Sends alerts via email

  • Triggers automatically on code push


πŸ“Œ What’s Next?

I plan to integrate more advanced testing stages, monitoring.


πŸ™Œ Conclusion

This project taught me how CI/CD isn't just about automation, it's about building reliable and scalable workflows. Jenkins remains one of the most powerful tools to get started with.

If you found this helpful, feel free to connect, share your feedback, or ask questions!

0
Subscribe to my newsletter

Read articles from Atharv Karpe directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Atharv Karpe
Atharv Karpe