Setting up Continuous Integration and Continuous Deployment (CI/CD) with Jenkins
In today’s fast-paced development world, automating the deployment process is essential. Continuous Integration and Continuous Deployment (CI/CD) pipelines enable developers to deliver code changes reliably and efficiently. In this blog post, I’ll walk you through setting up a CI/CD pipeline with Jenkins and running an application using Docker Compose.
DevOps tools that I would be using are GitHub, a code repo from where I would be fetching the code, Docker, to build our code, Docker compose, to make multiple containers, Jenkins; for automating our code fetching, code building and code deployment and this whole setup would be done in an AWS EC2 instance.
Architecture
Before I jump into the process, let’s understand the project's architecture. I would be using the node-todo-cicd project, automating the code build and deployment process, using Jenkins.
The key elements of our architecture include:
1. Git Users: These are the developers actively involved in the project. They work on enhancing the application, fixing issues, and then ultimately commit their changes before pushing them to the remote repository.
2. GitHub: This serves as the remote code repository where developers upload their code. Jenkins, in turn, fetches the code from the GitHub repository and proceeds with code building and deployment.
3. Jenkins: Jenkins is the primary tool for constructing continuous integration pipelines. When a Git user commits changes, Jenkins utilizes webhooks to detect these modifications and initiates the code-building and deployment process.
4. Docker: Docker plays a pivotal role as containerization software. It facilitates the code-building and deployment processes, ensuring consistency and reliability.
5. End Users: These individuals represent the clients who actively utilize the application.
By optimizing the synergy among these components, we achieve a robust and efficient development and deployment workflow.
Procedure:
Step 1: Fork the Repository
Fork the repository you want to work on. Simply click the “Fork” button on the repository’s GitHub page, and you’ll have a copy in your own GitHub account.
Step 2: Create a Connection to Jenkins
Make sure you have Jenkins installed and running on your server. Then, create a new Jenkins job. For this example, we’ll use a Pipeline job.
Creating Pipeline project with the name “Day24”:
GitHub Integration
In the Jenkins job configuration, paste the GitHub project URL.
And enable the “GitHub hook trigger for GITScm polling.” This allows Jenkins to automatically trigger builds when changes are pushed to the repository.
Step 3: CI/CD Setup
Write a Jenkinsfile to define the build, test, and deploy steps for your application. Here’s an example Jenkinsfile for a Node.js application:
pipeline {
agent { label "Agent1" }
stages{
stage("Clone Code"){
steps{
git url: "https://github.com/abhirajsingh2001/node-todo-cicd.git", branch: "master"
}
}
stage("Build and Test"){
steps{
sh "docker build . -t node-todo-app-cicd:v1"
}
}
stage("Push to Docker Hub"){
steps{
withCredentials([usernamePassword(credentialsId:"dockerHub",passwordVariable:"dockerHubPass",usernameVariable:"dockerHubUser")]){
sh "docker tag node-todo-app-cicd:v1 ${env.dockerHubUser}/node-todo-app-cicd:v1"
sh "docker login -u ${env.dockerHubUser} -p ${env.dockerHubPass}"
sh "docker push ${env.dockerHubUser}/node-todo-app-cicd:v1"
}
}
}
stage("Deploy"){
steps{
sh "docker-compose down && docker-compose up -d"
echo "Code Deployed"
}
}
}
}
Explanation:
1. Agent Configuration:
— The `agent` block specifies that this pipeline should run on an agent labeled “Agent1.” This means the pipeline will be executed on a Jenkins agent with the label “Agent1.”
2. Clone Code:
— In the “Clone Code” stage, the pipeline fetches the source code from the specified GitHub repository (`https://github.com/abhirajsingh2001/node-todo-cicd.git`) and the “master” branch using the `git` step.
3. Build and Test:
— In the “Build and Test” stage, the pipeline builds a Docker image named `node-todo-app-cicd:v1`. This is achieved using the `docker build` command, which builds the Docker image from the current directory (where the source code was cloned).
4. Push to Docker Hub:
— In the “Push to Docker Hub” stage, the pipeline pushes the Docker image to Docker Hub. This stage involves several steps:
— It uses the `withCredentials` block to securely access Docker Hub credentials (username and password) stored in Jenkins.
— The `docker tag` command tags the locally built Docker image with the Docker Hub repository and version (`${env.dockerHubUser}/node-todo-app-cicd:v1`).
— The `docker login` command authenticates with Docker Hub using the provided credentials.
— Finally, the `docker push` command uploads the tagged Docker image to Docker Hub.
5. Deploy:
— In the “Deploy” stage, the pipeline deploys the application using Docker Compose. This involves the following steps:
— It runs `docker-compose down` to stop and remove any previously running containers for this application.
— Then, it runs `docker-compose up -d` to start the application in detached mode, which ensures that the application continues to run in the background after Jenkins completes the pipeline.
— An “echo” statement is used to indicate that the deployment has been completed successfully.
Step 4: Webhooks
In your GitHub repository settings, configure a webhook to point to your Jenkins server’s URL with the /github-webhook/
path. Select the events you want Jenkins to trigger, typically "Push" events.
Now add the payload URL, it would be “http://{ip _address}/github-webhook”. Select the trigger events, in mycase, it is a push event.
Step 5: Test the Setup
Make a small code change, commit, and push it to your GitHub repository. Observe Jenkins automatically triggering a build and deploying the application when changes are pushed.
The output clearly illustrates that the modifications made by the deployer were promptly detected by the Jenkins pipeline. Subsequently, the sequence of actions initiated with code cloning, followed by the build and test phases, proceeded seamlessly. Afterward, the code was pushed to Docker Hub, and ultimately, the image was fetched from DockerHub, culminating in the successful deployment of the application.
Conclusion:
In this blog post, I’ve covered the essentials of setting up a CI/CD pipeline with Jenkins and running an application using Docker Compose. Automation is a powerful tool for modern development, making deployments more predictable and efficient. Now, armed with these skills, you’re ready to tackle more complex projects and contribute to the world of automation.