Building a Continuous Deployment Pipeline with Jenkins and Docker for iCoderBootstrap
Project: A step-by-step guide to automating deployment on AWS EC2
Jenkins is an open-source automation server that enables continuous integration and continuous delivery (CI/CD) of software development projects. One of the most important parts of your DevOps and CI/CD journey is the Declarative Pipeline Syntax of Jenkins. In this tutorial, we will create a new Jenkins job using the Declarative Pipeline Syntax. This example will help us understand how to create a basic pipeline using the Declarative Pipeline Syntax.
What is a Pipeline in Jenkins?
A pipeline is a collection of steps or jobs interlinked in a sequence. It is the foundation of "Pipeline-as-code"; treating the CD pipeline as a part of the application to be versioned and reviewed like any other code. The definition of a Jenkins Pipeline is written into a text file (called a Jenkinsfile
) which in turn can be committed to a project’s source control repository.
Why Use Declarative Pipeline Syntax?
Declarative is a more recent and advanced implementation of a pipeline as a code. It provides a more structured and opinionated way of defining pipelines. The Declarative Pipeline Syntax is designed to simplify the creation of pipelines and make them easier to read and maintain. It provides a more concise and readable syntax, making it easier for developers to understand and modify pipelines. Additionally, creating a Jenkinsfile
and committing it to source control provides several immediate benefits, including automatically creating a Pipeline build process for all branches and pull requests, and code review/iteration on the Pipeline (along with the remaining source code).
What is CI/CD?
CI/CD stands for Continuous Integration/Continuous Delivery (or Continuous Deployment) and is a software development approach that aims to automate and streamline the process of building, testing, and deploying code changes.
Continuous Integration refers to the practice of regularly merging code changes from multiple developers into a shared repository, where automated builds and tests are run to detect any issues or conflicts early on.
Continuous Delivery, on the other hand, is the practice of automatically deploying code changes to production environments after they have been tested and validated. This ensures that the code is always ready to be released to end-users, without any delays or manual intervention.
Continuous Deployment takes this one step further by automating the release process so that code changes are automatically pushed to production as soon as they pass all tests and checks.
CI/CD is an essential part of modern software development, as it allows teams to move faster, improve code quality, and reduce the risk of errors and downtime.
What Is a Build Job?
A Jenkins build job contains the configuration for automating a specific task or step in the application building process. These tasks include gathering dependencies, compiling, archiving, or transforming code, and testing and deploying code in different environments. Jenkins supports several types of build jobs, such as freestyle projects, pipelines, multi-configuration projects, folders, multibranch pipelines, and organization folders.
Docker is a popular containerization platform that allows users to package applications into containers. Containers are lightweight and portable, making it easy to deploy applications across different environments.
Amazon Elastic Compute Cloud (EC2) is a web service that provides scalable compute capacity in the cloud. It allows users to launch virtual machines and run applications on them, providing a scalable and reliable infrastructure for running applications in the cloud.
1.Steps to set up Jenkins on an AWS EC2 instance running Ubuntu:
Launch an AWS EC2 instance with Ubuntu as the operating system. During the launch, make sure to open port 8080 for Jenkins and port 8000 for the application in the security group.
Once the instance is launched and running, log in to the instance using SSH.
Install Java, Jenkins, and Docker by running the following commands:
sudo apt update sudo apt install openjdk-11-jre -y curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee \ /usr/share/keyrings/jenkins-keyring.asc > /dev/null echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \ https://pkg.jenkins.io/debian binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins.list > /dev/null sudo apt-get update sudo apt-get install jenkins sudo apt install docker.io -y sudo apt-get install -y docker-compose sudo usermod -aG docker jenkins
After the installation is complete, start Jenkins using the following command:
sudo systemctl start jenkins
Access Jenkins in a web browser by navigating to
http://<your-server-ip>:8080
. You will be prompted to enter the initial admin password, which can be found by running the following command:sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Follow the on-screen instructions to set up Jenkins, including installing any recommended plugins.
With these steps, you should be able to set up Jenkins on an AWS EC2 instance.
2.Steps to create a Dockerfile to build the image and a docker-compose file to run our container for the iCoderBootstrap application:
- Create a new file called
Dockerfile
in the root directory of your project and add the following content:
# Use the official nginx image as the base image
FROM nginx:1.21-alpine
# Copy the iCoderBootstrap files to the nginx web root directory
COPY . /usr/share/nginx/html
# Configure nginx to serve static resources
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
This Dockerfile uses the official nginx image as the base image and copies the contents of the current directory (which includes our iCoderBootstrap application) to the nginx web root directory. It also configures nginx to serve static resources.
- Create a new file called
docker-compose.yml
in the root directory of your project and add the following content:
version: '3.8'
services:
icoderbootstrap:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:80"
restart: always
command: nginx -g "daemon off;"
This docker-compose file defines a service named icoderbootstrap
which builds an image using the Dockerfile
we created earlier and runs a container based on that image. It maps port 8000 on the host machine to port 80 in the container, which is where nginx serves our iCoderBootstrap application. It also ensures that the container always restarts if it fails.
- Finally, make sure to create a file called
nginx.conf
in the root directory of your project that contains the following configuration:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
This configuration tells nginx to serve our iCoderBootstrap application by serving the index.html file from the /usr/share/nginx/html
directory.
That's it! With these files in place, you can build and run the iCoderBootstrap application using the following commands:
docker-compose build
docker-compose up -d
The -d
flag detaches the container and runs it in the background. You can access the application in your web browser by navigating to your server's public IP address on port 8000 (e.g. http://<server-ip>:8000
).
3.Steps to deploy the same application using a declarative pipeline:
Create a new Jenkins pipeline job: In the Jenkins dashboard, click on "New Item" and select "Pipeline". Give the job a name and click "OK".
Configure the pipeline: In the pipeline configuration page, select the "Pipeline script" option and enter the following pipeline script:
pipeline {
agent any
stages {
stage('Clone Repository') {
when {
expression {
!fileExists('iCoderBootstrap')
}
}
steps {
sh 'git clone https://github.com/Dhananjaykul/iCoderBootstrap.git'
}
}
stage('Build Docker Image') {
steps {
dir('/var/lib/jenkins/workspace/I-coder-cicd/iCoderBootstrap') {
sh 'docker build -t icoderbootstrap:latest .'
}
}
}
stage('Test Application') {
steps {
echo 'Code testing success'
}
}
stage('Deploy to Docker Container') {
steps {
dir('/var/lib/jenkins/workspace/I-coder-cicd/iCoderBootstrap') {
sh 'docker-compose down'
sh 'docker-compose up -d'
}
}
}
}
}
Save the pipeline configuration: Click on "Save" to save the pipeline configuration.
Run the pipeline job: Click on "Build Now" to run the pipeline job. The pipeline will clone the repository, build the Docker image, test the application, and deploy it to the Docker container.
Verify the deployment: Once the pipeline job is finished, verify that the application is deployed and running correctly by accessing it in a web browser using the EC2 instance's public IP address and port 8000.
Code Availability
The code for this project is available on GitHub at Click here . The repository includes all the necessary files and documentation to deploy the project on your own system. Feel free to fork the repository and make your own modifications to the code.
conclusion
Hence deployed a sample application using Jenkins declarative pipeline. We first cloned the repository, built a Docker image, tested the application, and finally deployed it to a Docker container using Docker Compose.You might encountered a few issues along the way, such as the missing Dockerfile and the incorrect directory path for Docker Compose. However,you will be able to resolve these issues by checking the directory structure and modifying the pipeline accordingly. Overall, we were able to successfully deploy the application using Jenkins declarative pipeline.