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: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.
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
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.
And wait for the installation of all basic plugins.
- Create an administrator account. It is strongly recommended to not use simple credentials if Jenkins is going to be publicly accessible.
Finally, as we completed all of these steps, we can start using Jenkins.
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.
- 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.
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.
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.
If you want to see the result of the test command, just hover the mouse over the list box and click the “Logs” button
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.