Building Docker Images as Part of a Jenkins Pipeline

CI/CD are crucial practices in modern software development, allowing teams to deliver high-quality software quickly and reliably. Docker, with its containerization capabilities, has become an essential tool in these processes, particularly when integrated with Jenkins

Building Docker Images as Part of a Jenkins Pipeline

Introduction

Continuous Integration and Continuous Deployment (CI/CD) are crucial practices in modern software development, allowing teams to deliver high-quality software quickly and reliably. Docker, with its containerization capabilities, has become an essential tool in these processes, particularly when integrated with Jenkins, a popular open-source automation server. In this post, we will explore how to build Docker images as part of a Jenkins pipeline, ensuring a seamless flow from code changes to deployment.

1. Overview of Jenkins Pipelines

Jenkins provides two main types of pipelines:

  • Declarative Pipelines: These pipelines use a simplified syntax that allows you to define the stages and steps clearly, making it easier for users who may not be familiar with Groovy scripting.
  • Scripted Pipelines: These pipelines provide more flexibility and control but require knowledge of Groovy scripting.

For the purpose of this post, we will focus on using Declarative Pipelines, as they are more straightforward and recommended for most CI/CD scenarios.

2. Setting Up Jenkins for Docker Integration

Before you can build Docker images in Jenkins, you need to set up Jenkins to work with Docker. Follow these steps:

  1. Install Jenkins: If you haven't already, install Jenkins on your server or local machine. You can find detailed installation instructions in the Jenkins documentation. If you're looking for a guide on how to install Docker, please check out my previous post here: Installing Docker on Different Platforms (Linux, Mac, Windows).
  2. Install Docker: Ensure that Docker is installed on the same server where Jenkins is running. This allows Jenkins to build and manage Docker containers. To learn about basic Docker comnands, please check my previous post: Docker Container Management: Essential Commands for Beginners.
  3. Install Required Plugins: To integrate Docker with Jenkins, you need to install some plugins:To install plugins, navigate to Manage Jenkins > Manage Plugins, and search for the required plugins under the Available tab.
    • Docker Pipeline Plugin: Provides support for using Docker containers within Jenkins pipelines.
    • Docker Plugin: Allows Jenkins to communicate with the Docker daemon.
  4. Configure Docker in Jenkins: Go to Manage Jenkins > Configure System. Scroll down to the Docker section, and configure the Docker host. You can specify the Docker socket path (e.g., /var/run/docker.sock) to allow Jenkins to communicate with Docker.

3. Creating a Dockerfile for Your Application

A Dockerfile is a text file that contains instructions for building a Docker image. Let's create a simple Dockerfile for a Node.js application as an example:

# Use the official Node.js image as the base
FROM node:14-alpine

# Set the working directory in the container
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the application code
COPY . .

# Expose the application port
EXPOSE 3000

# Start the application
CMD ["node", "server.js"]

This Dockerfile sets up a Node.js application by using a lightweight Node.js base image, installing dependencies, and copying the application code.

4. Building Docker Images in a Jenkins Pipeline

Now that we have our Dockerfile ready, let's create a Jenkins pipeline to build the Docker image. Here’s a sample Jenkinsfile:

pipeline {
    agent any

    stages {
        stage('Clone Repository') {
            steps {
                // Clone the repository containing the Dockerfile and application code
                git 'https://github.com/your-username/your-repo.git'
            }
        }

        stage('Build Docker Image') {
            steps {
                script {
                    // Build the Docker image
                    def app = docker.build("your-image-name:${env.BUILD_ID}")
                }
            }
        }

        stage('Run Tests') {
            steps {
                script {
                    // Run tests inside the Docker container
                    docker.image("your-image-name:${env.BUILD_ID}").inside {
                        sh 'npm test'
                    }
                }
            }
        }
    }

    post {
        success {
            echo 'Build and tests completed successfully.'
        }
        failure {
            echo 'Build or tests failed.'
        }
    }
}

In this Jenkinsfile, we define three main stages:

  • Clone Repository: This stage clones the Git repository containing the application code and Dockerfile.
  • Build Docker Image: In this stage, we use the docker.build command to build the Docker image, tagging it with the Jenkins build ID for versioning.
  • Run Tests: This stage runs tests inside the built Docker container. The docker.image(...).inside command starts a container from the specified image and executes the tests.

5. Pushing Docker Images to a Registry

Once the Docker image is built and tested, you may want to push it to a Docker registry (such as Docker Hub, Amazon ECR, or a private registry) for later use. You can add an additional stage in the Jenkinsfile for this purpose:

stage('Push Docker Image') {
    steps {
        script {
            // Log in to the Docker registry
            docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-credentials-id') {
                // Push the image to the registry
                app.push()
            }
        }
    }
}

In this stage:

  • We log in to the Docker registry using the credentials stored in Jenkins (configured under Credentials).
  • The app.push() command pushes the built Docker image to the specified Docker registry.

6. Best Practices for CI/CD with Docker and Jenkins

To maximize the efficiency and reliability of your CI/CD pipeline, consider the following best practices:

  1. Use Caching: Take advantage of Docker layer caching to speed up builds. Structure your Dockerfile to optimize caching by placing less frequently changing commands at the top.
  2. Automate Tests: Always run tests within your pipeline to ensure that code changes do not introduce new bugs.
  3. Tag Images Properly: Use semantic versioning for tagging your Docker images. This helps with version management and rollback if necessary.
  4. Clean Up Resources: Regularly clean up unused Docker images and containers on your Jenkins server to save disk space.
  5. Monitor Build Performance: Keep track of build times and resource usage to identify bottlenecks and optimize your CI/CD process.

Conclusion

Building Docker images as part of a Jenkins pipeline is a powerful way to automate your CI/CD process. By integrating Docker into Jenkins, you can streamline your build and deployment processes, ensuring that your applications are always in a deployable state.

In this post, we covered the essential steps to set up Jenkins for Docker integration, create a Dockerfile, build Docker images, run tests, and push images to a registry. By following best practices, you can optimize your CI/CD pipeline for efficiency and reliability.

Read next

Setting Up Jenkins with JCasC (Jenkins Configuration as Code)

In today’s software development, managing Jenkins through its GUI can become challenging as the complexity and number of jobs grow. Jenkins Configuration as Code (JCasC) provides a powerful solution to this by allowing Jenkins configuration to be defined and managed via code

Running Jenkins as a Docker Container

Jenkins as a Docker container is a powerful way to leverage the benefits of containerization in your CI/CD workflows. Docker allows you to create, manage, and deploy Jenkins environments efficiently, enabling consistent builds across various environments.