Docker - Continuous Integration



Continuous Integration with Docker is the process of automating the creation, testing, and deployment of Docker containers in a Development Workflow. It means that changes committed into a version control system like Git will automatically build Docker images from updated code in a CI pipeline. The image is then sent through a series of automated tests that check if the application works as expected.

Assuming the tests pass, the image can be pushed to a container registry and deployed in staging or production environments. Docker with CI/CD provides consistency across all development and deployment stages by ensuring exactly the same environment from development to production. This helps in minimizing environment-related issues.

In this chapter, lets understand how to build a basic CI/CD pipeline with Docker integrated into it.

How to build a CI/CD pipeline with Docker?

In this section, we will understand how to create an end-to-end CI/CD pipeline using Docker, and Jenkins, and build, test, and run a Java application through it.

Step 1: Install Docker

The first step is to install Docker on your machine. You can refer to one of our previous chapters and follow the installation instructions for your operating system by downloading Docker from the Docker website.

Step 2: Run Jenkins in a Docker Container

Next, You can run the following command to start Jenkins in a Docker container −

$ docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts
Docker Continuous Integration 1

The above command will pull the latest Jenkins LTS image and run it. You can access the Jenkins dashboard at http://localhost:8080.

Step 3: Initial Jenkins Setup

1. Access Jenkins − Open your browser and navigate to http://localhost:8080.

2. Unlock Jenkins − Follow the instructions to get the initial admin password.

Docker Continuous Integration 2

Run the following command to get the password −

$ docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
Docker Continuous Integration 3

3. Install Suggested Plugins − After entering the password, choose "Install suggested plugins."

Docker Continuous Integration 4

Docker Continuous Integration 5

4. Create Admin User − Create your admin user to manage Jenkins.

Docker Continuous Integration 6

Step 4: Configure Docker in Jenkins

Install Docker Pipeline Plugin

  • Go to Jenkins Dashboard -> Manage Jenkins -> Manage Plugins -> Available.
  • Search for "Docker Pipeline" and install it.
Docker Continuous Integration 7

Add Docker Hub Credentials

  • Go to Jenkins Dashboard -> Manage Jenkins -> Manage Credentials.
  • Add a new set of credentials with your Docker Hub username and password.
Docker Continuous Integration 8

Step 5: Create a Java Application

Create a simple Java application with the following structure −

my-java-app/
 src/
    main/
       java/
           org/
               example/
                   Main.java
    test/
        java/
            org/
                example/
                    MainTest.java
 Dockerfile
 Jenkinsfile
 pom.xml

App.java

package org.example;
public class Main {
   public static void main(String[] args) {
      System.out.println("Hello, Docker CI/CD with Jenkins!");
   }
}

AppTest.java

package org.example;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class MainTest {
   @Test
   public void shouldAnswerWithTrue() {
      assertTrue(true);
   }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
   http://maven.apache.org/xsd/maven-4.0.0.xsd">
   
   <modelVersion>4.0.0</modelVersion>

   <groupId>org.example</groupId>
   <artifactId>my-java-app</artifactId>
   <version>1.0-SNAPSHOT</version>

   <properties>
      <maven.compiler.source>8</maven.compiler.source>
      <maven.compiler.target>8</maven.compiler.target>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>

   <dependencies>
      <!-- JUnit 4 dependency -->
      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.13.2</version>
         <scope>test</scope>
      </dependency>
   </dependencies>
</project>

Step 6: Update the Dockerfile

Create a Dockerfile in the root of your project −

FROM maven:3.6.3-jdk-8 AS build
WORKDIR /app
COPY pom.xml .
COPY src /app/src
RUN mvn clean package

FROM openjdk:8-jre-alpine
WORKDIR /app
COPY --from=build /app/target/my-java-app-1.0-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]

Step 7: Update the Jenkinsfile

Create a Jenkinsfile in the root of your project to define your CI/CD pipeline −

pipeline {
   agent any

   tools {
      maven 'Maven 3.6.3' // Define the Maven version installed on your Jenkins server
   }

   stages {
      stage('Build') {
         steps {
            script {
               // Build the Docker image
               docker.build("my-java-app:${env.BUILD_ID}")
            }
         }
      }
      stage('Test') {
         steps {
            script {
               // Run tests inside the Docker container
               docker.image("my-java-app:${env.BUILD_ID}").inside {
                  sh 'mvn test'
               }
            }
         }
      }
      stage('Push') {
         steps {
            script {
               // Push the Docker image to Docker Hub
               docker.withRegistry('https://index.docker.io/v1/', 'dockerhub-credentials') {
                  docker.image("my-java-app:${env.BUILD_ID}").push('latest')
               }
            }
         }
      }
      stage('Deploy') {
         steps {
            script {
               // Deploy the Docker image to the production environment
               sh 'docker run -d -p 8080:8080 my-java-app:latest'
            }
         }
      }
   }
   post {
      always {
         cleanWs()
      }
   }
}

Step 8: Configure Jenkins Job

1. Create a New Job − Go to Jenkins Dashboard -> New Item.

  • Select "Pipeline" and name it my-java-app-pipeline.
  • In the pipeline configuration, select "Pipeline script" and copy the Jenkinsfile content here.
  • Alternatively, you can also Pipeline script from SCM and choose "Git" and provide the repository URL where your Java application is hosted.
  • Specify the branch to build (e.g., main or master).
  • Specify the Jenkinsfile path.
Docker Continuous Integration 9

Docker Continuous Integration 10

2. Build the Job − Save the configuration and click "Build Now" to start the pipeline.

Step 9: Monitor the Pipeline

  • Build Stage − The Docker image is built using the Dockerfile.
  • Test Stage − The application tests are run inside the Docker container using the mvn test command. The MainTest.java file is executed, and the results are reported.
  • Push Stage − The Docker image is pushed to Docker Hub.
  • Deploy Stage − The Docker image is deployed to a server.

By following these steps, you now have a fully functional CI/CD pipeline that includes a test stage for your Java application using Docker and Jenkins.

Conclusion

In this chapter, we have discussed how to create a fully functional CI/CD pipeline using Docker, and Jenkins, and build, test, and run a Java application. Docker's containerization ensures consistency across development, testing, and deployment environments for improved reliability and reproducibility. Jenkins automates this pipeline from building the Docker image and running tests to deploying the application, hence rapid feedback for continuous improvement.

Testing methodologies in such a setup using Maven and JUnit facilitates strong methods of testing for quality and reliability. Equipped with these best practices, teams can drive efficient, scalable, resilient software delivery that continues to work congruently with the demands of agile development and modern-day deployment cycles.

FAQs on Docker Continuous Integration

1. How do I integrate Docker with Jenkins for CI/CD?

The first step to integrate Docker with Jenkins is to install a Docker plugin on your Jenkins server, allowing interaction of Jenkins with Docker and enabling it to build images, run containers, and push them to registries. After that, you have the option to define your CI/CD pipeline in Jenkins with Docker commands for building and deploying applications.

2. How can I use Docker Compose with Jenkins?

Docker Compose is used to define and manage multi-container applications. You can use the Docker Compose plugin in Jenkins for complex deployments like spinning up several containers in the right order, configuration, and so on; this is particularly useful when having multiple services within an application.

3. How do I set up a Jenkins pipeline for building Docker images?

You can create a Jenkins pipeline with Jenkinsfile defining all your steps for building and deployment of your Docker image. This pipeline extracts the source code from source control, creates a Docker image, runs tests, pushes the image to some registry, and deploys it to the target environment.

Advertisements