"Building Your First Jenkins Declarative CI/CD Pipeline for Deploying a Django Notes App on AWS EC2"

Pravesh SudhaPravesh Sudha
8 min read

๐Ÿ’ก Introduction

Welcome to the exciting world of DevOps! In this blog post, I'll guide you through setting up your very first Jenkins Declarative CI/CD pipeline to deploy a Django Notes application on an AWS EC2 instance. Whether you're a newcomer to the world of Continuous Integration and Continuous Deployment (CI/CD) or looking to expand your skills, this step-by-step guide is designed with beginners in mind.

๐Ÿ’ก Prerequisites

  1. AWS Account: Ensure you have an active AWS account. If you don't have one, you can sign up. Don't worry; there's a free tier available that you can use to follow along.

  2. Basic Knowledge of EC2: Familiarize yourself with Amazon EC2 (Elastic Compute Cloud) concepts. If you're new to EC2, it's Amazon's virtual servers in the cloud. You can learn the basics on the AWS site.

๐Ÿ‘‰ What is Jenkins Declarative Pipeline?

Jenkins is a popular open-source automation server used for building, testing, and deploying code. The Declarative Pipeline in Jenkins is a way to define an entire build/test/deploy pipeline in a Jenkinsfile, using a simplified and structured syntax.

๐Ÿ‘‰ Our Project: Django Notes App

We'll be deploying a simple Django Notes application. This hands-on experience will help you understand the complete flow from source code to deployment in a controlled and automated manner.

๐Ÿ’ก Starting Ec2 Instance

  • Navigate to the AWS Management Console and go to the EC2 dashboard.

  • Click on "Launch Instance" to create a new virtual machine.

  • Choose Ubuntu (AMI) for your instance, and select an instance type (t2.micro) that suits your application's needs.

  • Add tags for better identification, and configure security groups to allow SSH access.

  • Review your configurations and click "Launch."

    Connecting to EC2 Instance via SSH:

    • Once your EC2 instance is running, select it from the EC2 dashboard.

    • In the instance details, find the public IP address or DNS name.

    • Open a terminal on your local machine.

        chmod "your-key.pem" 400
        ssh -i "your-key.pem" ec2-user@your-instance-ip
      
    • If you are using a different operating system or connecting from a different environment, adapt the command accordingly.

๐Ÿ’ก Installing Jenkins on Ubuntu machine

Step 1: Install Java Development Kit (JDK):

Jenkins is built on Java, so the first step is to install the Java Development Kit. We recommend using OpenJDK, a free and open-source implementation of the Java Platform.

sudo apt update
sudo apt install openjdk-11-jdk

To verify the installation, run:

java -version

You should see information about the installed Java version.

Step 2: Install Jenkins:

Jenkins is not available in the default Ubuntu repositories, so we need to add the Jenkins repository and install it.

sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
  https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
  https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
  /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins

Start the Jenkins service:

sudo systemctl start jenkins

Enable Jenkins to start on boot:

sudo systemctl enable jenkins

Step 3: Enable port in Security group:

By default, Port 8080 and 8000 is not enabled in your instance security group, you have to select the instance, go to the Security tab -> Click on the Security group and then click Edit Inbound rules. Add ports 8080 and 8000 to the list with Anywhere IPv4 like shown below:

Step 4: Access Jenkins Web Interface:

Jenkins runs on port 8080 by default. Open your web browser and navigate to http://<Your-Public-Ip-address>:8080. You will be prompted to unlock Jenkins, and the initial password can be found in the Jenkins server logs.

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

You can also see the password from:

sudo systemctl status jenkins

Follow the on-screen instructions to complete the setup. Install suggested plugins or customize your plugin selection based on your requirements.

Step 5: Create Jenkins Admin User:

After plugin installation, create an admin user for Jenkins.

๐Ÿ’ก Creating a Pipeline:

Before creating Pipeline, we need to install docker and docker-compose and clone the project in the Ubuntu system:

git clone  https://github.com/Pravesh-Sudha/django-notes-app.git
sudo apt install docker.io -y
sudo apt install docker-compose -y

# To avoid permission denied errors in docker,
# Run the following command after installing docker to grant permission:
sudo usermod -aG docker $USER
sudo usermod -aG docker jenkins
sudo reboot 
# This will reboot the system and disconnet your terminal
# You can use the ssh command to reconnect it after a few minutes.
  1. Go to New Item -> Give a name to pipeline (eg Jenkins-blog pipeline) and select Pipeline Project.

  2. Fill in the Details in the General tab as Follows:

    like Github project: https://github.com/Pravesh-Sudha/django-notes-app.git

    and tick mark the GitHub book trigger in Build triggers

    1. Scroll down to the pipeline section, Write the following pipeline Configuration:

       pipeline {
           agent any 
      
           stages{
               stage("Clone Code"){
                   steps {
                       echo "Cloning the code"
                       git url:"https://github.com/Pravesh-Sudha/django-notes-app.git", branch: "main"
                   }
               }
               stage("Build"){
                   steps {
                       echo "Building the image"
                       sh "docker build -t my-note-app ."
                   }
               }
               stage("Push to Docker Hub"){
                   steps {
                       echo "Pushing the image to docker hub"
                       withCredentials([usernamePassword(credentialsId:"dockerHub",passwordVariable:"dockerHubPass",usernameVariable:"dockerHubUser")]){
                       sh "docker tag my-note-app ${env.dockerHubUser}/my-note-app:latest"
                       sh "docker login -u ${env.dockerHubUser} -p ${env.dockerHubPass}"
                       sh "docker push ${env.dockerHubUser}/my-note-app:latest"
                       }
                   }
               }
               stage("Deploy"){
                   steps {
                       echo "Deploying the container"
                       sh "docker-compose down && docker-compose up -d"
      
                   }
               }
           }
       }
      

      This Jenkinsfile represents a declarative pipeline in Jenkins, which defines a series of stages to automate the process of building, packaging, and deploying a Dockerized Django notes app. Let's break down the different sections of this Jenkinsfile:

      1. Pipeline Declaration:

       pipeline {
           agent any
      
      • pipeline: Declares the start of a Jenkins pipeline.

      • agent any: Specifies that the pipeline can run on any available agent (Jenkins worker node).

2. Stages Section:

        stages {
            // Stages go here
        }
  • stages: Defines a block where different stages of the pipeline are declared.

3. Clone Code Stage:

        stage("Clone Code") {
            steps {
                echo "Cloning the code"
                git url: "https://github.com/Pravesh-Sudha/django-notes-app.git", branch: "main"
            }
        }
  • stage("Clone Code"): Declares a stage named "Clone Code."

  • steps: Defines a block containing the steps to be executed within this stage.

  • echo "Cloning the code": Prints a message to the console.

  • git url: "https://github.com/LondheShubham153/django-notes-app.git", branch: "main": Clones the specified Git repository from the given URL and branch.

4. Build Stage:

        stage("Build") {
            steps {
                echo "Building the image"
                sh "docker build -t my-note-app ."
            }
        }
  • stage("Build"): Declares a stage named "Build."

  • steps: Defines a block containing the steps to be executed within this stage.

  • echo "Building the image": Prints a message to the console.

  • sh "docker build -t my-note-app .": Executes a shell command to build a Docker image named "my-note-app."

5. Push to Docker Hub Stage:

        stage("Push to Docker Hub") {
            steps {
                echo "Pushing the image to Docker Hub"
                withCredentials([usernamePassword(credentialsId:"dockerHub",passwordVariable:"dockerHubPass",usernameVariable:"dockerHubUser")]){
                    sh "docker tag my-note-app ${env.dockerHubUser}/my-note-app:latest"
                    sh "docker login -u ${env.dockerHubUser} -p ${env.dockerHubPass}"
                    sh "docker push ${env.dockerHubUser}/my-note-app:latest"
                }
            }
        }
  • stage("Push to Docker Hub"): Declares a stage named "Push to Docker Hub."

  • steps: Defines a block containing the steps to be executed within this stage.

  • echo "Pushing the image to Docker Hub": Prints a message to the console.

  • withCredentials: Allows the use of credentials stored in Jenkins for authentication.

  • sh "docker tag my-note-app ${env.dockerHubUser}/my-note-app:latest": Tags the Docker image with the appropriate repository and tag.

  • sh "docker login -u ${env.dockerHubUser} -p ${env.dockerHubPass}": Logs in to Docker Hub using the provided credentials.

  • sh "docker push ${env.dockerHubUser}/my-note-app:latest": Pushes the Docker image to Docker Hub.

6. Deploy Stage:

        stage("Deploy") {
            steps {
                echo "Deploying the container"
                sh "docker-compose down && docker-compose up -d"
            }
        }
  • stage("Deploy"): Declares a stage named "Deploy."

  • steps: Defines a block containing the steps to be executed within this stage.

  • echo "Deploying the container": Prints a message to the console.

  • sh "docker-compose down && docker-compose up -d": Stops and removes existing Docker containers using docker-compose down and then start the application in detached mode (-d) using docker-compose up.

Before running the Pipeline, we need to add the environment variable of docker hub credentials as Specified in the Push to Docker Hub Stage:

Go To Dashboard -> Manage Jenkins -> Credentials. Click System Credentials -> Global credentials -> Add credentials.

Select Username and Password in the drop-down menu. Enter your Dockerhub username and password and fill in the ID section with dockerHub.

Click save and apply to apply the change.

๐Ÿ’กRunning the Pipeline

Go to the Pipeline project -> Click Build now. You will see an output like this:

Your application docker container will also be running at http://your-ip-addresss:8000. A sample of the application looks like this:

๐Ÿ’ก Auto-Building the Project

If you want this project to build whenever there is a push commit to the repo go to project settings.

  1. Select Webhook -> Add Webhooks.

  1. In the payload URL, add http://<your-ip-address>:8080/github-webhook

  2. Select Send me everything, to get notified about every build.

  3. Make a commit to the repo and see the auto build working.

๐Ÿ’ก Conclusion

In wrapping up our journey, you've mastered the basics of Jenkins Declarative CI/CD pipelines and successfully deployed a Django Notes App on an AWS EC2 instance. We covered everything from setting up Jenkins to connecting via SSH and witnessed the automation magic in action.

This hands-on experience is your launchpad into the world of DevOps. Armed with the ability to automate builds, tests, and deployments, you're now well-equipped for the dynamic realm of continuous improvement.

As you venture forward, remember that DevOps is a journey of continual learning. Use this foundation to explore advanced topics, refine your workflows, and stay ahead in the ever-evolving landscape of DevOps. Happy automating, and welcome to the world of DevOps excellence!

Happy Coding!! :)

2
Subscribe to my newsletter

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

Written by

Pravesh Sudha
Pravesh Sudha

I am a Self Taught developer from India with major interest in open source, devops and Coding. Pursuing a Bachelors in Philosophy has helped me a lot to drive right in my career. Landed in tech, now I am exploring tech blogging for fun