Docker and Java Application examples
In this tutorial, we will show you how to Dockerize a Java Application (an executable Jar file).
Tested with
- Docker 19.03
- Ubuntu 19
- Java 8
- Maven
At the end of the article, we will create an executable Jar file and run inside a docker container.
1. Project Directory
1.1 A standard Maven project structure. See the Dockerfile
at the root of the project? We only need this Dockerfile
text file to dockerize the Java Application.
Note The .idea
folders and docker-java-app.iml
are IDEA configuration files, ignore it.
2. Maven and Java Application
Now, we will create an executable Jar file. This Jar will use jsoup HTML parser
to find all links from a URL or web page.
2.1 Project dependencies.
<?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>com.mkyong</groupId>
<artifactId>docker-java-app</artifactId>
<version>1.0</version>
<name>docker-java-app</name>
<url>https://www.mkyong.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>1.8</java.version>
<jsoup.version>1.12.1</jsoup.version>
<junit.version>5.4.0</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>find-links</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- create executable jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.mkyong.App</mainClass>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<!-- copy dependencies / jars to ${project.build.directory}/lib/ -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib/
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.2 A Simple Java application.
package com.mkyong;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class App {
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.err.println("[Usage] jar -jar find-links.jar <url>");
return;
}
String url = args[0];
for (String link : findLinks(url)) {
System.out.println(link);
}
}
private static Set<String> findLinks(String url) throws IOException {
Document doc = Jsoup.connect(url)
.data("query", "Java")
.userAgent("Mozilla")
.cookie("auth", "token")
.timeout(3000)
.get();
Set<String> links = new HashSet<>();
Elements elements = doc.select("a[href]");
for (Element element : elements) {
links.add(element.attr("href"));
}
return links;
}
}
3.3 Maven package and run it. It will create an executable jar file at target/find-links.jar
, and copy jsoup
dependencies to the target/lib
folder
Note – Forget about the JUnit 5
dependencies, we are not going to create any unit test.
$ cd ~/projects/docker-java-app
$ mvn package
$ tree
target
├── find-links.jar
├── lib
│ ├── apiguardian-api-1.0.0.jar
│ ├── jsoup-1.12.1.jar
│ ├── junit-jupiter-api-5.4.0.jar
│ ├── junit-jupiter-params-5.4.0.jar
│ ├── junit-platform-commons-1.4.0.jar
│ └── opentest4j-1.1.1.jar
$ java -jar target/find-links.jar
[Usage] jar -jar find-links.jar <url>
$ java -jar target/find-links.jar https://google.com
https://play.google.com/?hl=en&tab=w8
https://www.google.com/calendar?tab=wc
/intl/en/about.html
https://photos.google.com/?tab=wq&pageId=none
https://drive.google.com/?tab=wo
https://translate.google.com.my/?hl=en&tab=wT
//...
Done, next, we will start this find-links.jar
in a docker container.
4. Docker File
A Dockerfile
is a text file, contains all the commands to assemble the docker image.
4.1 Review the commands in the Dockerfile
, it creates a docker image base on openjdk:8-jdk-alpine
, an alpine linux with openjdk-8
installed, changed the working directory with WORKDIR
and copy the executable jar and its dependencies to this path /usr/local/runme/
, and run the jar file with ENTRYPOINT
.
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/find-links.jar
ARG JAR_LIB_FILE=target/lib/
# cd /usr/local/runme
WORKDIR /usr/local/runme
# copy target/find-links.jar /usr/local/runme/app.jar
COPY ${JAR_FILE} app.jar
# copy project dependencies
# cp -rf target/lib/ /usr/local/runme/lib
ADD ${JAR_LIB_FILE} lib/
# java -jar /usr/local/runme/app.jar
ENTRYPOINT ["java","-jar","app.jar"]
Note We can find more base images from docker hub
5. Dockerize Java Application
Now, we need to run docker’s commands to parse the Dockerfile
to assemble a docker image.
5.1 Go to the folder containing Dockerfile
.
$ cd project
$ pwd
/home/mkyong/projects/docker-java-app
$ ls -lsah
4.0K drwxr-xr-x 5 mkyong mkyong 4.0K Jan 21 18:35 .
4.0K drwxr-xr-x 6 mkyong mkyong 4.0K Jan 20 15:27 ..
4.0K -rw-r--r-- 1 mkyong mkyong 352 Jan 21 18:26 Dockerfile
4.0K -rw-r--r-- 1 mkyong mkyong 3.3K Jan 21 18:13 pom.xml
4.0K -rw-r--r-- 1 mkyong mkyong 267 Jan 21 18:35 readme.md
4.0K drwxr-xr-x 4 mkyong mkyong 4.0K Jan 20 15:27 src
4.0K drwxr-xr-x 10 mkyong mkyong 4.0K Jan 21 18:17 target
5.2 Let build a docker image with sudo docker build -t name:tag .
$ pwd
/home/mkyong/projects/docker-java-app
$ sudo docker build -t docker-java:1.0 .
[sudo] password for mkyong:
Sending build context to Docker daemon 1.206MB
Step 1/7 : FROM openjdk:8-jdk-alpine
---> a3562aa0b991
Step 2/7 : ARG JAR_FILE=target/find-links.jar
---> Running in 8eaabda7c1ce
Removing intermediate container 8eaabda7c1ce
---> 50eedc2911be
Step 3/7 : ARG JAR_LIB_FILE=target/lib/
---> Running in 7a6c30690589
Removing intermediate container 7a6c30690589
---> 053f8ebac2a0
Step 4/7 : WORKDIR /usr/local/runme
---> Running in 91ab9f0f41d3
Removing intermediate container 91ab9f0f41d3
---> eadff9da3d5d
Step 5/7 : COPY ${JAR_FILE} app.jar
---> f52d6a8440c8
Step 6/7 : ADD ${JAR_LIB_FILE} lib/
---> fd693617a411
Step 7/7 : ENTRYPOINT ["java","-jar","app.jar"]
---> Running in 1dce276e93b3
Removing intermediate container 1dce276e93b3
---> 94b4a465425f
Successfully built 94b4a465425f
Successfully tagged docker-java:1.0
5.3 Start a docker container, run the app.jar
file during startup. When the Jar file finished running, exit the docker container.
$ sudo docker run -t docker-java:1.0 https://google.com
https://play.google.com/?hl=en&tab=w8
https://www.google.com/calendar?tab=wc
/intl/en/about.html
https://photos.google.com/?tab=wq&pageId=none
https://drive.google.com/?tab=wo
https://translate.google.com.my/?hl=en&tab=wT
https://maps.google.com.my/maps?hl=en&tab=wl
https://books.google.com.my/bkshp?hl=en&tab=wp
https://mail.google.com/mail/?tab=wm
//...
Done, we dockerize a Java application.
6. FAQs
6.1 How to access the docker container’s file system or shell, for debugging?
A: Comment the ENTRYPOINT
in Dockerfile
to avoid the docker container to run the jar file during startup.
#...
# cd /usr/local/runme
WORKDIR /usr/local/runme
#...
# java -jar /usr/local/runme/app.jar
# ENTRYPOINT ["java","-jar","app.jar"]
Rebuild the docker image.
$ sudo docker build -t docker-java:1.0 .
Rerun it, since we defined WORKDIR
in the Dockerfile
file, the docker container will start a shell and change the directory to /usr/local/runme
, start debugging here.
# -i
$ sudo docker run -it docker-java:1.0
# This is docker container shell!
/usr/local/runme # ls -lsah
total 16
4 drwxr-xr-x 1 root root 4.0K Jan 21 10:38 .
4 drwxr-xr-x 1 root root 4.0K Jan 21 10:38 ..
4 -rw-r--r-- 1 root root 3.4K Jan 21 10:17 app.jar
4 drwxr-xr-x 2 root root 4.0K Jan 21 10:38 lib
/usr/local/runme # cd lib
/usr/local/runme/lib # ls -lsah
total 1128
4 drwxr-xr-x 2 root root 4.0K Jan 21 10:38 .
4 drwxr-xr-x 1 root root 4.0K Jan 21 10:38 ..
4 -rw-r--r-- 1 root root 2.1K Jan 15 10:29 apiguardian-api-1.0.0.jar
388 -rw-r--r-- 1 root root 387.8K Jan 15 10:28 jsoup-1.12.1.jar
132 -rw-r--r-- 1 root root 131.0K Jan 15 10:29 junit-jupiter-api-5.4.0.jar
500 -rw-r--r-- 1 root root 499.9K Jan 15 10:29 junit-jupiter-params-5.4.0.jar
88 -rw-r--r-- 1 root root 87.2K Jan 15 10:29 junit-platform-commons-1.4.0.jar
8 -rw-r--r-- 1 root root 7.0K Jan 15 10:29 opentest4j-1.1.1.jar
/usr/local/runme/lib # which java
/usr/bin/java
/usr/local/runme/lib # java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)
OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)
Note If the docker container is running, we can access it directly with this command
$ sudo docker exec -ti container_name /bin/bash
$ sudo docker exec -ti container_name /bin/sh
6.2 How to ship the docker image for deployment?
A: The faster way is to push the image to the docker hub and pull it from the server.
# client
# tag
$ sudo docker image tag docker-java:1.0 mkyong2002/docker-java:1.0
# push
$ sudo docker image push mkyong2002/docker-java:1.0
# server
$ sudo docker pull mkyong2002/docker-java:1.0
Note
You may like this Docker + Spring Boot examples
Download Source Code
$ cd docker-java-app
$ mvn package
$ java -jar target/find-links.jar https://google.com
//dockerize
// create a docker image
$ sudo docker build -t docker-java:1.0 .
// run it
$ sudo docker run -t docker-java:1.0 https://google.com
How to do same on Windows machine as I don’t see any base image for Windows maven on dockerize hub. can you share some example.
is this step [COPY ${JAR_FILE} app.jar] is renaming the find-links.jar to app.jar?