The introduction of new tools such as Jenkins and Docker has helped to boost productivity. Over the past years, the way we build software has undergone significant changes. Nowadays, developers can create new technologies within months and deploy them. In this tutorial, we will set up Jenkins in a Docker container and use Groovy script to build and run a simple Java app.

We can automate the building, testing, and deployment of software by running tools like Jenkins. This eases continuous integration (CI) and continuous delivery (CD). Including running apps in Docker also solves several incompatibility issues.

1. Our Goal: Set up Jenkins in a Docker container and use Groovy script to build and run a simple Java application

In this tutorial, we will set up Jenkins in a Docker container and use Groovy script to build and run a simple java application.

Prerequisites:

  • Basic knowledge of Command line, Git, Java and Maven
  • Understanding of Docker and its commands. 
  • A Java IDE – In this tutorial, we will use IntelliJ Idea, but you can use any IDE of your choice 
  • You can download work files from our test repository. https://github.com/joto2itgix/java-hello-world

Creating a demo Java application:

The goal of this tutorial is not to teach us how to create a java app with maven. Therefore, we will be using the example created by https://github.com/niwasawa/java-hello-world-with-maven.

In order to be able to build a java application, we need a pom.xml file and for your ease, the example is uploaded inside the project directory. Our pom.xml file looks like this.

<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/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>info.maigo.lab.hello</groupId>
  <artifactId>maigolab_hello</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>maigolab_hello</name>
  <url>http://maven.apache.org</url>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <configuration>
          <mainClass>info.maigo.lab.hello.App</mainClass>
          <arguments>
            <argument>niwasawa</argument>
            <argument>maigolab</argument>
          </arguments>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <!-- https://mvnrepository.com/artifact/com.mashape.unirest/unirest-java -->
    <dependency>
      <groupId>com.mashape.unirest</groupId>
      <artifactId>unirest-java</artifactId>
      <version>1.4.9</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.json/json -->
    <dependency>
      <groupId>org.json</groupId>
      <artifactId>json</artifactId>
      <version>20170516</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

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

</project>

2. Setting up Jenkins in Docker

First step is to create a Docker network:

docker network create –subnet=172.68.0.0/24 jenkins
e46fdb73c236cbb86f60c708dad24d3e9f788c6778d456b5ef86098225a531a2

By creating a network we can make it easier and simpler to access and manage the Jenkins container.

As we set up Jenkins in Docker, we need to remember the goal of our setup: Build and execute a Java app with a container. For this to happen, we need to execute some commands inside the container. In order to do this, we need to provide some dependencies.

Create a Dockerfile in any directory, and in the Dockerfile add:

FROM jenkins/jenkins:lts

USER root

RUN apt-get update
RUN apt-get \
    --yes --allow-downgrades \
    install \
    curl \
    vim \
    telnet \
    wget \
    maven

RUN java -version

RUN chown -R jenkins /var/jenkins_home

RUN chmod 777 /tmp

We will use the official Jenkins image from the Docker hub and will install simple apps like maven, wget, telnet, and vim. We don’t install Java since Jenkins is Java-based and it is already be provided.
Now we build the new image.

docker build . -t devops_jenkins:1

Once we trigger the Docker build process, it will take some time to complete.

Sending build context to Docker daemon  3.584kB 
Step 1/6 : FROM jenkins/jenkins:lts 
lts: Pulling from jenkins/jenkins 
647acf3d48c2: Extracting [==============================================>]  51.25MB/54.93MB 
832e288237bc: Download complete 
ea194d1bd1da: Download complete 
98569593b9fd: Download complete 
dfe249e8cdf2: Download complete 
0f6f2e6d37bb: Download complete 
07fcb98649b6: Download complete 
1e33c26b1882: Download complete 
7b24f0e29fe1: Downloading [====================> ]  29.09MB/72.01MB 
4d90ef3a8f3b: Download complete 
d98c8e675bea: Download complete 
b45fc2bf9fd7: Downloading [=> ] 1.617MB/76.39MB 
d6e1fda9effc: Waiting 
3635a44047f2: Pulling fs layer 
486e1776d3bc: Pulling fs layer 
41233d151800: Waiting 
14a67803c2b3: Waiting 


Step 2/6 : USER root 
---> Running in 3311c3136571 
Removing intermediate container 3311c3136571 
---> 82d327b83686
Step 3/7 : RUN apt-get update 
---> Running in 81502814f6c8 
Get:1 http://security.debian.org/debian-security bullseye-security InRelease [44.1 kB] 
Get:2 http://security.debian.org/debian-security bullseye-security/main amd64 Packages [102 kB] 
Get:3 http://deb.debian.org/debian bullseye InRelease [116 kB]
…...


Step 4/7 : RUN apt-get     --yes --allow-downgrades     install     curl     vim     telnet     wget     maven     default-jdk 
---> Running in 6d1151f768c7 
Reading package lists... 
Building dependency tree... 
Reading state information... 
The following additional packages will be installed: 
alsa-topology-conf alsa-ucm-conf at-spi2-core ca-certificates-java dbus 
default-jdk-headless default-jre default-jre-headless fonts-dejavu-extra 
java-common libaopalliance-java libapache-pom-java libapparmor1 libasound2 
libasound2-data libatinject-jsr330-api-java libatk-bridge2.0-0 
libatk-wrapper-java libatk-wrapper-java-jni libatk1.0-0 libatk1.0-data 
libatspi2.0-0 libavahi-client3 libavahi-common-data libavahi-common3 
libcdi-api-java libcommons-cli-java libcommons-io-java libcommons-lang3-java 
libcommons-parent-java libcups2 libcurl4 libdbus-1-3 libdrm-amdgpu1 
libdrm-common libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdrm2 libe
….
Step 5/7 : RUN java -version 
---> Running in 74344eed09f2 
openjdk version "11.0.13" 2021-10-19 
OpenJDK Runtime Environment Temurin-11.0.13+8 (build 11.0.13+8)                                                                                                                                                                                                                
OpenJDK 64-Bit Server VM Temurin-11.0.13+8 (build 11.0.13+8, mixed mode)                                                                                                                                                                                                       
Removing intermediate container 74344eed09f2                                                                                                                                                                                                                                   
---> cb41b5bbc3fe 
Step 6/7 : RUN chown -R jenkins /var/jenkins_home 
---> Running in 5bd07d9e37b7 
Removing intermediate container 5bd07d9e37b7 
---> 4e6d6fd447cf 
Step 7/7 : RUN chmod 777 /tmp 
---> Running in ea72a1b2f8d1 
Removing intermediate container ea72a1b2f8d1 
---> 0260f6f8eb8e 
Successfully built 0260f6f8eb8e 
Successfully tagged devops_jenkins:1

The process undergoes through 3 major steps:

  • Download official jenkins image cached layers
  • Install additional dependencies
  • Update permissions of working folders

After we have successfully built the new image, we can run it.

docker run \
    -v /tmp/jenkins/home:/var/jenkins_home \
    --net jenkins --ip 172.68.0.10 \
    --detach \
    --name devops_jenkins devops_jenkins:1

We are running the container with the newly created image. In order to do this, we are attaching it to the Jenkins network and choosing a random IP address from the network available range.

The second important step is to map the Jenkins home folder. Thereby every time the container restarts, we are not going to lose any of progress that we have made.

Once the container is executed, we can check if it is available with the following command.

docker container ls 

The above command verifies that the Jenkins container is up and running.

Jenkins container is set up and running

The boot process will take some time, we can check if the container is booting properly with the following command:

docker logs devops_jenkins --follow
2022-01-04 13:40:35.372+0000 [id=34]    INFO    jenkins.InitReactorRunner$1#onAttained: Completed initialization 
2022-01-04 13:40:35.604+0000 [id=24]    INFO    hudson.WebAppMain$3#run: Jenkins is fully up and running

3. First run

Now we can type http://172.168.0.10:8080 in any modern browser. The same IP we chose earlier. 

We will go through a couple of simple pages for initial configuration.

  • Unlock. The first task is to unlock the web portal. This is done by providing a randomly generated password that is saved in the jenkins working folder.

If you choose the same mount point as in the example /var/jenkins_home -> /tmp/jenkins/home you can use this command to retrieve the value.

cat /tmp/jenkins/home/secrets/initialAdminPassword

Unlock Jenkins

Paste it in the “Administration password” field and hit enter.

  • Choose plugins. Jenkins comes with all needed plugins preinstalled for our goal. Plugins can always be installed through the Settings menu. Thus, it is safe to just hit “Install suggested plugins” button.
Customize Jenkins: Install suggested plugins

And wait for the installation of all basic plugins.

Getting Started: jenkins dokcer build
  • Create an administrator account. It is strongly recommended to not use simple credentials if Jenkins is going to be publicly accessible.
Jenkins Docker build Create First Admin User

Finally, as we completed all of these steps, we can start using Jenkins.

jenkins docker build Jenkins is ready setup complete

4. First job in Jenkins

Once we are redirected to the first page, we can create a new job. Either by clicking on this banner or from the left navigation menu.

First job on jenkins docker build
  • Build. First we will create a job using Jenkins pre build Groovy Script Language. 
    • From the new window input any name. We will use “Build” so it is clear what the job goal is. 
    • From all options choose “Pipeline”. This is the job type that supports Groovy Scripts.
    • And click ok.
Build Jenkins create a job using Groovy Script

From the job options scroll to the bottom where you will find the “Pipeline section” and paste:

pipeline {
    agent any
    stages {
        stage('Clone java repo') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        git branch: "master",
                        url: "https://github.com/joto2itgix/java-hello-world.git"
                    }
                }
            }
        }
        stage('MVN Install') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        sh "mvn compile"
                    }
                }
            }
        }
    }
}

So what does this job do? It is split into two steps called “Stages”:

  • First one downloads our git repo in the “${WORKSPACE}” jenkins job working directory. You can see the output here /tmp/jenkins/home/workspace/Build
  • Second one run “mvn compile” that will build the maven project.
Use Groovy Sandbox in Jenkins for First Job in jenkins docker build

You can save and build the project by clicking “Build Now” from the left navigation menu.

5. Test Java Application

With the same steps as the Build job, we can create one that will test the app.

We will call it “Test” and the groovy code is as follows:

pipeline {
    agent any
    stages {
        stage('Clone java repo') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        git branch: "master",
                        url: "https://github.com/joto2itgix/java-hello-world.git"
                    }
                }
            }
        }
        stage('MVN Install') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        sh "mvn compile"
                    }
                }
            }
        }
        stage('MVN Test') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        sh "mvn test"
                    }
                }
            }
        }
    }
}

Here we can see an additional step that will run one command more “mvn test”. This will run the test after the project is built.

As you can see the status of Test Pipeline looks different, containing one step more.

status of test pipeline jenkins

If you want to see the result of the test command, just hover the mouse over the list box and click the “Logs” button

stage view logs jenkins docker build first job

6. Run job

The last job to create is a job that will actually run our test app.

pipeline {
    agent any
    stages {
        stage('Clone java repo') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        git branch: "master",
                        url: "https://github.com/joto2itgix/java-hello-world.git"
                    }
                }
            }
        }
        stage('MVN Install') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        sh "mvn compile"
                    }
                }
            }
        }
        stage('MVN Execute') {
            steps {
                script {
                    dir("${WORKSPACE}") {
                        sh "mvn exec:java"
                    }
                }
            }
        }
    }
}

The job looks a lot like the “Test”. The only difference is the command run in the last step.

We are replacing “mvn test” with “mvn exec:java”

Again we can check the result in the logs section.

7. Conclusion

To sum up, we have learned how to set up and run Jenkins with Docker. We also built, tested, and ran a Java application code hosted on Github. For more expert content & tutorials please visit our blog section. If you don’t find what you’re looking for contact us for consultation on your exact case.

Author: Vladimir Dimitrov

DevOps Engineer @ ITGix

Leave a Reply

Your email address will not be published.