Unlock the full potential of your CI pipeline with powerful continuous deployment capabilities
Deploying software releases quickly and reliably is essential in today’s fast-paced software development landscape. One way to achieve this is through Continuous Deployment (CD), which can help automate and streamline the software delivery process.
In this blog, we’ll explore how continuous deployment (CD) can help you enhance your CI pipeline and release software faster and with more confidence. Building on the concepts covered in our previous post, “Accelerate Development with Jenkins Pipelines and Continuous Integration,” we’ll delve into the benefits of CD and how it can be integrated with your existing pipeline using Jenkins.
Before delving into the concept of continuous deployment, let’s first understand what our R&D team hopes to achieve.
Imagine the following workflow:
A developer commits code to GitHub, which triggers a build process. The code then undergoes a variety of tests, after which you may want to store the artifact. Finally, the critical moment arrives when you want to deploy the new version to your environments, whether it be staging or production.
The Benefits of an Isolated Deployment Approach
The ability to deploy independently both within and to your pipeline is a key factor in maintaining a stable environment. You can choose to automate deployment to certain environments, like staging, for testing, while retaining manual deployment for production to maintain greater control. Additionally, the ability to rollback to a previous version is vital for ensuring system stability and user confidence, especially in the event of issues or errors.
By deploying independently and selectively, you can achieve a more streamlined and efficient release process.
Jenkins and the Evolution of Continuous Deployment
To achieve our desired pipeline workflow, we’ll utilize Jenkins and create a comprehensive pipeline that emphasizes both automatic and manual deployment.
Prerequisites:
- A virtual machine with a docker engine
Setting Up Your Environment for Jenkins
Unlike the previous blog post, we’re now utilizing a different image for our Jenkins setup: 2.387-jdk11-hello-world-blog-2
docker run -d \
--name jenkins -p 8080:8080 -u root -p 50000:50000 \
-v /var/run/docker.sock:/var/run/docker.sock \
naturalett/jenkins:2.387-jdk11-hello-world-blog-2
# Validate the Jenkins Container
docker ps | grep -i jenkins
# Retrieve the Jenkins initial password:
docker exec jenkins bash -c -- 'cat /var/jenkins_home/secrets/initialAdminPassword'
# Connect to Jenkins on the localhost
open http://localhost:8080
Continuing from our previous blog, we’ll be building upon our pipeline and continuing to use the Groovy language.
Our approach includes the following:
- Creation of a static deployment job that can be triggered manually by developers outside of the pipeline.
- Integration of the same deployment job into the pipeline for automatic triggering during the deployment stage.
This approach offers several benefits, one of these is the ability to maintain a separate job for deployment history, which is independent of the pipeline itself. However, it’s also possible to deploy during the pipeline without using a static job if this better aligns with your preferences and requirements.
Are you looking to enhance your DevOps skills and learn how to implement continuous integration using Jenkins container pipelines? Join my course, where you’ll gain practical experience in various pipeline scenarios and master production skills. Take the first step towards becoming a DevOps expert today.
Hands-On Mastering DevOps — CI and Jenkins Container Pipelines
Creating a Static Deployment Job in Jenkins
The static Jenkins job that we’re using consists of the following four parts:
- Parameter: Obtaining the version that needs to be deployed.
- Initialization: Retrieving the built image from the current machine.
- Deployment: Deploying the image onto the current machine.
- Post Action: Notifying the user with a description of their service after deployment.
def customImage
pipeline {
agent {
docker {
image 'docker:19.03.12'
args '-v /var/run/docker.sock:/var/run/docker.sock'
}
}
parameters {
string description: 'Version to deploy', name: 'version', trim: true
}
stages {
stage('Initialization') {
steps {
script {
customImage = docker.image("${params.version}")
}
}
}
stage('Deployment') {
steps {
script {
customImage.run("""-d -p 80${env.BUILD_ID}:81 --name hello-world-${env.BUILD_ID}""")
}
}
}
}
post {
success {
script {
echo 'Successfully deployed'
currentBuild.description = """Visit: http://localhost:80${env.BUILD_ID}"""
}
}
}
}
If you have launched the Jenkins version mentioned earlier, you can now try out the pipeline on your own: http://localhost:8080/job/deployment_job/
Automatically triggering deployment jobs within the pipeline
An alternative approach would be to define the deployment stage during the pipeline itself. To achieve this, we’ve added a deployment stage that can be executed automatically during the pipeline run. In the example provided below, we’ve skipped the deployment stage using a predefined expression. However, you can customize this expression as per your requirements.
def skipDeployment = false, imageName = "naturalett/hello-world"
def shortCommit, currentDate
pipeline {
agent {
...
}
triggers {
...
}
stages {
stage('Clone') {
...
}
stage('Build') {
...
}
stage('Test') {
...
}
stage('Deployment Within the pipeline') {
when { expression { skipDeployment != true } }
steps {
script {
customImage.run("""-d -p 8${env.BUILD_ID}:81 --name hello-world-${env.BUILD_ID}""")
}
}
}
}
post {
...
}
If you have launched the Jenkins version mentioned earlier, you can now try out the pipeline on your own: http://localhost:8080/job/my-second-pipeline/
Enhancing accessibility integration between the pipeline and the static job
In our pipeline, we have defined a post
section that runs upon the completion of a pipeline run. Within the post-success section, we’ve included the following two features:
- Description: This feature sets the description to reflect the version of the built Docker image.
- Badge: This feature contains a link that directs users to the deployment job along with the version to be deployed, based on the current job that built the image.
def imageName = "naturalett/hello-world", skipDeployment = true
def currentDate, shortCommit
pipeline {
agent {
docker {
...
}
triggers {
...
}
stages {
...
}
post {
success {
script {
echo 'Set description for jenkins pipeline'
desc = """Version: ${imageName}:${currentDate}-${env.BUILD_ID}-${shortCommit}"""
if (skipDeployment != true) {
desc += """\nVisit: http://localhost:80${env.BUILD_ID}"""
}
currentBuild.description = desc
echo 'Set badge'
def url = env.JENKINS_URL + "job/deployment_job/buildWithParameters" + \
"?version=${imageName}:${currentDate}-${env.BUILD_ID}-${shortCommit}"
addBadge(icon : "success.gif", text: "Press to deploy", link: url)
}
}
}
}
Summarize
We have gained an understanding of how Continuous Deployment (CD) can optimize the Continuous Integration (CI) pipeline and simplify the software delivery process. We explain the benefits of deploying software releases independently and selectively within the pipeline, achieving a more efficient release process. Using Jenkins and Groovy language, we also demonstrate how to create a static deployment job that can be triggered manually by developers outside of the pipeline, as well as how to integrate the same deployment job into the pipeline for automatic triggering during the deployment stage.
Are you looking to enhance your DevOps skills and learn how to implement continuous integration using Jenkins container pipelines? Join my course, where you’ll gain practical experience in various pipeline scenarios and master production skills. Take the first step towards becoming a DevOps expert today.
Hands-On Mastering DevOps — CI and Jenkins Container Pipelines