How To Install Java On Docker Container
Intro to managing and running a containerized Coffee Leap Kicking awarding
Docker is a platform for packaging, deploying, and running applications in containers. Information technology tin run containers on any system that supports the platform: a developer'south laptop, systems on "on-prem," or in the cloud without modification. Images, the packages Docker uses for applications, are truly cross-platform.
Java microservices are a skillful target for Docker. Running a service in a container augments development with a common target platform for development, testing, and deployment. Containers are also an excellent first step toward moving toward a flexible and price-effective deject compages.
In this tutorial, nosotros'll package a Spring Boot application, run information technology, and look at the dissimilar commands for managing images and containers.
Docker setup and installation
Install Docker
Outset, start by installing the Docker desktop tools institute here. Download the correct installer for your operating organization and follow the instructions.
Next, verify the installation with the post-obit two commands:
$ docker --version Docker version 18.03.1-ce, build 9ee9f40 $ docker run hello-earth Unable to find image 'hi-world:latest' locally latest: Pulling from library/hello-world 9bb5a5d4561a: Pull complete Digest: sha256:f5233545e43561214ca4891fd1157e1c3c563316ed8e237750d59bde73361e77 Condition: Downloaded newer image for howdy-earth:latest Howdy from Docker! This message shows that your installation appears to be working correctly. ....
The starting time control checks docker's version. Your version may be different, depending on your platform.
Docker run hello-world does what information technology sounds like – it runs an prototype named hello-world.
Get-go, it looks for this image on the local system. Since it is not there information technology downloads it from Docker Hub. And so it runs the container, which displays a message telling us everything'southward working fine, and then it spells out the process it took to run the paradigm.
Docker looked for a local copy of the hello-earth image. Since it wasn't present, it went to Docker Hub and downloaded the latest paradigm. Once the image was completely downloaded, information technology ran hello-world in a container.
Jump Boot application
To keep the tutorial focused on Docker, we'll use an existing project, which is explained in this Jump tutorial. It'south a pocket-size web application that manages employee records.
You can run the awarding with this command line:
java -Dspring.profiles.active=default -jar target/spring-boot-ops.war
It serves a unmarried page at http://localhost:8080 /springbootapp/employees:
Permit'southward get correct to work running this in docker.
Build and run a Docker application
Building an Image
You create images with a Dockerfile, which lists the components and commands that make upwards the packet.
Start, create the file:
# Alpine Linux with OpenJDK JRE FROM openjdk:viii-jre-alpine # copy WAR into image COPY spring-boot-app-0.0.1-SNAPSHOT.war /app.war # run application with this command line CMD ["/usr/bin/coffee", "-jar", "-Dspring.profiles.active=default", "/app.war"]
Dockerfiles are a list of commands that docker performs to build an epitome. We'll have a closer look at these commands beneath.
It's a best do to build images in a "clean" directory, as docker build'south default beliefs is to copy the working directory to the image. Place this file in a new folder at the top of your project named docker.
You can't utilise relative paths in Dockerfiles, then you'll need to modify our pom.xml to identify the war file in the target directory.
Side by side, add the output directory property to the spring-boot-maven-plugin.
This copies the jar into the docker directory every bit part of the bundle build target. Brand sure your pom.xml has this block in the plugins section:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> <configuration> <mainClass>com.stackify.Application</mainClass> <outputDirectory>${project.basedir}/docker</outputDirectory> </configuration> </execution> </executions> </plugin> Then, build the image:
$ docker build -t jump-kick-app:latest . Sending build context to Docker daemon 2.048kB Step one/3 : FROM openjdk:8-jre-alpine viii-jre-alpine: Pulling from library/openjdk ff3a5c916c92: Pull complete a8906544047d: Pull complete a790ae7377b0: Pull complete Digest: sha256:795d1c079217bdcbff740874b78ddea80d5df858b3999951a33871ee61de15ce Status: Downloaded newer image for openjdk:eight-jre-alpine ---> c529fb7782f9 Stride 2/3 : COPY target/spring-boot-app-0.0.1-SNAPSHOT.war /app.state of war ---> d19bfa9fdfa7 Step 3/three : CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.agile=default", "/app.war"] ---> Running in 04bf7e97079a Removing intermediate container 04bf7e97079a ---> 04872b157605 Successfully built 04872b157605 Successfully tagged spring-boot-app:latest
I'll cover the contents of the file and what happens during the build afterwards this initial image is running.
Finally, y'all can take a look at the build results:
$ docker image ls REPOSITORY TAG Paradigm ID CREATED SIZE jump-kicking-app latest 04872b157605 28 seconds agone 128MB openjdk 8-jre-alpine c529fb7782f9 iii days ago 82MB
Docker image ls lists the images on our system. Your new image is there, named spring-boot-app as specified in the build command. You lot will also run into openjdk, which docker created as part of the build procedure.
Running a Docker container
Now run the application in a container:
$ docker run -d -p 8080:8080 spring-boot-app:latest e9418201d112b15b94a489ab9995d966807a2171e844810567b110f2b9be01ec
Point a web browser at http://localhost:8081/springbootapp/employees and you run into the employee record.
Accept a look at what's running:
$ docker ps IMAGE STATUS PORTS NAMES spring-kick-app:latest Upwardly two minutes 0.0.0.0:8080->8080/tcp eloquent_varaham
Docker ps displays the running containers on the host motorcar.
Nosotros meet the container is up and running! You take a Spring Boot application running on Docker.
The command line to run this container had 3 arguments:
- -d run as a daemon process and disassemble from the console
- -p map port 8080 on the host automobile to port 8080 in the container
- jump-kick-app:latest name:tag of the image to run
Docker images and containers
If you await again at the headings above, you run into you congenital an image and so ran a container. This terminology is important.
Containers
Merely put, Docker runs the applications in a container. It'south important to annotation that these containers don't run in and are not virtual machines. They run on Linux and share the host system's kernel with each other. Implementations on non-Linux platforms such as macOS and Windows x use a Linux virtual machine for the Docker runtime.
Within containers, applications are isolated from one another and the underlying infrastructure. Each container has a virtual filesystem and appears to take its own kernel. This simplifies application packaging and problems with an application are isolated to a container, protecting the rest of the machine.
Images
Images contain everything needed to run the container. "Everything" includes not only the code and libraries for the application, but also the operating arrangement besides.
Let's look at our Dockerfile over again:
# Tall Linux with OpenJDK JRE FROM openjdk:8-jre-alpine # re-create fatty WAR Re-create jump-kick-app-0.0.1-SNAPSHOT.war /app.war # runs application CMD ["/usr/bin/coffee", "-jar", "-Dspring.profiles.agile=default", "/app.war"]
The start line tells docker where to start building; FROM openjdk:eight-jre-alpine. This is the name of an existing image that provides the OpenJDK JRE on Alpine Linux. Alpine Linux delivers a lightweight, secure, and fast container for running Java applications.
The next line copies the web jar to the root of the image filesystem. A dockerfile can include several COPY directives, and it can exist used to copy entire file copse.
The last line is the command that will be executed to start our container. CMD accepts an array of strings that make up the command line, similar to Runtime.exec.
When y'all built this image nosotros saw this in the build output:
Status: Downloaded newer prototype for openjdk:viii-jre-alpine
Docker retrieved that prototype as part of the build, and then it applied the rest of the file to that paradigm.
You can view the list of steps that have been taken to build any prototype:
$ docker history jump-boot-app:latest Paradigm CREATED BY SIZE fb9139a8c8b8 /bin/sh -c #(nop) CMD ["/usr/bin/java" "-ja… 0B d19bfa9fdfa7 /bin/sh -c #(nop) Re-create file:f4a155b9ed7a8924… 46.2MB c529fb7782f9 /bin/sh -c set -10 && apk add --no-cache o… 77.8MB <missing> /bin/sh -c #(nop) ENV JAVA_ALPINE_VERSION=viii… 0B <missing> /bin/sh -c #(nop) ENV JAVA_VERSION=8u151 0B <missing> /bin/sh -c #(nop) ENV PATH=/usr/local/sbin:… 0B <missing> /bin/sh -c #(nop) ENV JAVA_HOME=/usr/lib/jv… 0B <missing> /bin/sh -c { echo '#!/bin/sh'; echo 'set… 87B <missing> /bin/sh -c #(nop) ENV LANG=C.UTF-eight 0B <missing> /bin/sh -c #(nop) CMD ["/bin/sh"] 0B <missing> /bin/sh -c #(nop) ADD file:093f0723fa46f6cdb… 4.15MB This output is a list of images. The last eight are "missing" their image ids because they are not nowadays on your organization.
The top three, however, do have ids. The "created by" columns for these images displayed what pace in our build created them:
- CMD – the directive from our Dockerfile
- Copy – copying our jar to the prototype
- apk – the Alpine Linux bundle tool installing openjre package
Running docker history –no-trunc spring-kicking-app:latest provides the complete commands. The output is too wide to display here.
Take a look at docker image ls again:
docker epitome ls REPOSITORY TAG IMAGE ID CREATED SIZE leap-boot-app latest fb9139a8c8b8 12 hours agone 128MB openjdk 8-jre-tall c529fb7782f9 four days ago 82MB
There are two images: both yours and openjdk. Their ids match the ids of the commencement and third images in our history. The second image was an intermediate stage and doesn't be.
Openjdk is still present on your system, while spring-boot-app exists equally a prepare of diffs to the base paradigm. Docker manages images and containers as layers, which conserves retentivity and deejay space.
Managing Docker applications
Starting and stopping Docker containers
Docker ps shows us what is running:
$ docker ps IMAGE STATUS PORTS NAMES bound-boot-app:latest Up 2 minutes 0.0.0.0:8080->8080/tcp eloquent_varaham
The awarding is still up. Information technology's running in a container named eloquent_varaham.
We utilize the container name to command it. Allow'southward stop is:
$ docker finish eloquent_varaham eloquent_varaham
When you lot bank check docker ps, it's gone:
$ docker ps CONTAINER ID IMAGE COMMAND
And if you lot try to open the index page again, it fails.
But the container is still there. Let's expect over again:
$ docker ps -a Epitome Status PORTS NAMES jump-boot-app:latest Exited (143) two minutes ago eloquent_varaham
Adding -a shows us stopped containers.
Nosotros tin restart an existing container instead of creating a new one:
$ docker restart eloquent_varaham eloquent_varaham $ docker ps -a Prototype Status PORTS NAMES spring-kicking-app:latest Up 22 seconds 0.0.0.0:8080->8080/tcp eloquent_varaham
The container is running again and you can open access the web app.
But you lot can stop and remove and container too:
$ docker stop eloquent_varaham eloquent_varaham $ docker rm eloquent_varaham eloquent_varaham $ docker ps -a CONTAINER ID IMAGE PORTS NAMES
Docker rm removes a container, simply it must exist stopped first.
Looking inside containers
Get-go a new container. Not the different port mapping statement:
$ docker run -d -p 8081:8080 spring-kick-app:latest 69e430267b4347a6d9cbfc5b7fcce368187622c219105e8f3634b9c8116bb20b $ docker ps IMAGE COMMAND PORTS NAMES spring-kick-app:latest "/usr/bin/coffee -jar …" 0.0.0.0:8080->8080/tcp sad_swartz
It's running once more, in a container named sad_swartz. Point your browser at port 8081 to load the page. You can remap container ports to different host ports on the command line.
Now take a look at the container logs:
$ docker logs sad_swartz . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.0.1.RELEASE) 2022-06-10 02:36:53.032 INFO 1 --- [ chief] c.s.Awarding : Starting Awarding ...
Docker logs
displays the container'due south output.
You tin can also attach a shell to our container:
$ docker exec -it sad_swartz sh / # ps PID USER Fourth dimension Control ane root 0:52 /usr/bin/java -jar -Dspring.profiles.active=default /app.war 46 root 0:00 sh fifty root 0:00 ps / # ls app.war dev dwelling house media proc run srv tmp var bin etc lib mnt root sbin sys usr / #
Docker'due south exec choice executes a program within a container. Since the Alpine epitome is minimalist, you need to utilize sh. You lot can but execute commands that are already in the prototype.
The -it flags allow us to interact with the beat out.
Building a ameliorate epitome
All country, including the filesystem, lives only for the lifetime of the container. When you rm the container, y'all destroy the land also.
If y'all want to preserve information, it needs to exist stored outside of the container. Let'due south demonstrate this by mapping the application log to a directory on the host system.
Kickoff, add a logback configuration to the application:
<?xml version="1.0" encoding="UTF-eight"?> <configuration> <include resource="org/springframework/boot/logging/logback/base.xml"/> <appender name="FILE" course="ch.qos.logback.core.FileAppender"> <file>/var/log/Application/awarding.log</file> <suspend>true</append> <encoder> <pattern>%-7d{yyyy-MM-dd HH:mm:ss:SSS} %m%north</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="FILE" /> </root> </configuration> And then modify your Dockerfile to utilise it:
FROM openjdk:8-jre-tall Copy spring-boot-app-0.0.i-SNAPSHOT.war /app.war Re-create logback.xml /logback.xml CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.active=default", "-Dlogging.config=/logback.xml", "/app.war"]
You're copying the logback.xml into the prototype, and adding the logging configuration to the command line.
The logging configuration places the application logs in /var/log/Application/.
Rebuild the image:
$ docker build -t jump-boot-app:latest . Sending build context to Docker daemon 131.1MB Footstep i/iv : FROM openjdk:eight-jre-alpine ---> c529fb7782f9 Step 2/4 : Re-create target/jump-kick-app-0.0.one-SNAPSHOT.war /app.war ---> Using cache ---> d19bfa9fdfa7 Step 3/4 : COPY src/main/resources/logback.xml /logback.xml ---> Using enshroud ---> d62f97d9900d Stride four/4 : CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.active=default", "-Dlogging.config=/logback.xml", "/app.state of war"] ---> Using enshroud ---> fb9139a8c8b8 Successfully built fb9139a8c8b8 Successfully tagged spring-kicking-app:latest
Docker didn't download the openjdk:8-jre-alpine image since docker has information technology cached locally.
Look at the build command. You specify an paradigm tag with -t. This is the same tag that y'all pass to docker run. Y'all provide the working directory last.
At present, you demand to map the directory to a directory on the host when you lot run our container:
$ docker run -d -v /var/log/app:/var/log/Application/ -p 8080:8080 spring-boot-app:latest
The -five option maps /var/log/app on our host organization to /var/log/Awarding/ in the container.
When you lot run this control, you tin see a log file created in the mapped directory.
You've been letting docker assign names to your containers. You lot tin override this with –proper noun:
$ docker run -d --proper noun bootapp -5 /var/log/app:/var/log/Awarding/ -p 8080:8080 bound-kick-app:latest 57eb3f1998f503dc146d1f3b7ab9a6b221a939537be17ffc40fd410e2b72eda3 $ docker ps IMAGE Condition PORTS NAMES jump-kick-app:latest Up two seconds 0.0.0.0:8080->8080/tcp bootapp
Adding packages
When you looked at your image's history, you saw the command for adding the jre to Tall. Yous tin can add together packages to Alpine in your Dockerfile, too. Let'due south add bash to the container.
Offset, add the APK control to our Dockerfile:
# Alpine Linux with OpenJDK JRE FROM openjdk:8-jre-alpine RUN apk add --no-cache bash # Re-create State of war Re-create spring-boot-app-0.0.one-SNAPSHOT.war /app.war # copy fatty State of war Copy logback.xml /logback.xml # runs application CMD ["/usr/bin/java", "-jar", "-Dspring.profiles.agile=default", "-Dlogging.config=/logback.xml", "/app.state of war"]
So build the image with the same directives as before:
$ docker build -t spring-kicking-app:latest . Sending build context to Docker daemon 40MB Step 1/5 : FROM openjdk:8-jre-alpine ---> c529fb7782f9 Step ii/5 : RUN apk add --no-enshroud fustigate ---> Using cache ---> 3b0c475c9bd0 Step 3/5 : Re-create spring-boot-ops.state of war /app.war ---> c03bd6c6ace5 Stride 4/5 : COPY logback.xml /logback.xml ---> b2f899ebec17 Step five/5 : CMD ["/usr/bin/coffee", "-jar", "-Dspring.profiles.active=default", "-Dlogging.config=/logback.xml", "/app.war"] ---> Running in 3df30746d7a8 Removing intermediate container 3df30746d7a8 ---> cbbfb596a092 Successfully built cbbfb596a092 Successfully tagged spring-kick-app:latest
The output is a lilliputian different this time. You can see where bash was installed in step ii.
Finally, after you run the container, yous can vanquish in with bash:
$ docker exec -it bootapp bash bash-4.iv# ls app.war etc logback.xml proc sbin tmp bin home media root srv usr dev lib mnt run sys var bash-4.4#
Passing command line variables
So far, you've been running the Spring Kicking application with the agile profile set to default. You may want to build a single jar with unlike profiles and and so select the correct one at runtime. Permit's modify our paradigm to take the active profile every bit a command line argument.
First, create a beat script in the docker directory that runs the web application:
#!/bin/sh coffee -Dspring.profiles.active=$1 -Dlogging.config=/logback.xml -jar /app.state of war
This script accepts a single argument and uses it every bit the name of the active profile.
And so, change your Dockerfile to use this script to run the application:
# Alpine Linux with OpenJDK JRE FROM openjdk:8-jre-alpine RUN apk add --no-enshroud fustigate # copy fat WAR Re-create leap-kick-app-1.0.0-SNAPSHOT.war /app.state of war # copy fat WAR COPY logback.xml /logback.xml COPY run.sh /run.sh ENTRYPOINT ["/run.sh"]
Dockerfile offers two mechanisms for starting a container; the ENTRYPOINT and the CMD. Only put, the ENTRYPOINT is the plan that is executed to beginning the container and CMD is the statement passed to that program.
The default ENTRYPOINT is /bin/sh -c. Until now, you were passing our Java command array to a shell.
Now, the dockerfile is copying the script to the image and then defining every bit the image's ENTRYPOINT. At that place is no CMD.
Build this image and and so run information technology with dev every bit the final argument on the command line:
$ docker run -d --name bootapp -v /var/log/app:/var/log/Application/ -p 8080:8080 leap-kick-app:latest dev
And then have a look at the logs for the active contour:
$ grep profiles /var/log/webapp/application.log 2022-06-11 00:33:50:016 The post-obit profiles are agile: dev
You can see that the profile setting was passed into the JVM.
Publishing images
Nosotros've only used the image on your evolution system. Eventually, y'all'll want to distribute information technology to clients or production systems. This is done with a registry, where images are pushed with a name and tag and then pulled when they are run as containers. Yous saw this in activity at the showtime of this tutorial when docker pulled the hello-world image for you.
The first step is to create an account on Docker Cloud. Go and create an account in that location if you don't already have 1.
Adjacent, log in to the Docker registry on our development system:
$ docker login Username: baeldung Password: Login Succeeded
Next, tag the image. The format for tags is username/repository:tag. Tags and repository names are effectively freeform.
Tag the image and so list the images on your organization to run across the tag:
$ docker tag spring-boot-app baeldung/spring-kick-app:.0.0.1 $ docker epitome ls REPOSITORY TAG IMAGE ID CREATED SIZE spring-boot-app latest f20d5002c78e 24 minutes ago 132MB baeldung/leap-boot-app ane.00 f20d5002c78e 24 minutes agone 132MB openjdk 8-jre-alpine c529fb7782f9 4 days ago 82MB
Note that the new epitome tag and the original prototype have the same image ID and size. Tags don't create new copies of images. They're pointers.
Now you can push the image to Docker Hub:
$ docker push baeldung/spring-boot-app:.0.0.1 The push refers to repository [docker.io/baeldung/spring-boot-app] 8bfb0f145ab3: Pushed 2e0170d39ba4: Pushed 789b0cedce1e: Pushed f58f29c8ecaa: Pushed cabb207275ad: Mounted from library/openjdk a8cc3712c14a: Mounted from library/openjdk cd7100a72410: Mounted from library/openjdk i.00: assimilate: sha256:4c00fe46080f1e94d6de90717f1086f03cea06f7984cb8d6ea5dbc525e3ecf27 size: 1784
Docker button accepts a tag proper name and pushes information technology to the default repository, which is Docker Hub.
Now, if you visit your account area on hub.docker.com, you can encounter the new repository, the image, and the tag.
At present you can pull the image downwards and run it on any system:
$ docker run -d --name bootapp -v /var/log/app:/var/log/Awarding/ -p 8080:8080 ericgoebelbecker/spring-kicking-app:.0.0.1 dev Unable to find image 'baeldung/spring-kick-ops:1.00' locally 1.00: Pulling from baeldung/spring-boot-ops b0568b191983: Pull complete 55a7da9473ae: Pull complete 422d2e7f1272: Pull complete 3292695f8261: Pull consummate Digest: sha256:4c00fe46080f1e94d6de90717f1086f03cea06f7984cb8d6ea5dbc525e3ecf27 Status: Downloaded newer image for baeldung/spring-boot-app:.0.0.1
This is the output of run on a different system from the ane I built on. Like to the mode yous ran hello-world, you lot passed the paradigm tag to docker run. And since the paradigm was not available locally, Docker pulled information technology from Docker Hub, assembled it, and ran information technology.
Conclusion
Docker is a robust platform for building, managing, and running containerized applications. In this tutorial, we installed the tools, packaged a Leap Boot application, looked at how nosotros tin can manage containers and images, and and so added some improvements to our awarding.
Finally, we published our image to Docker Hub, where information technology can be downloaded and run on any Docker-enabled host.
Now that you understand the nuts continue experimenting and see how you tin can use Docker to parcel and distribute your Java applications.
As always, the source lawmaking for this tutorial is available over on Github.
Stackify'south Application Peformance Management tool, Retrace keeps Java applications running smoothly with APM, server health metrics, and error log integration. Download your free two calendar week trial today!
- About the Author
- Latest Posts
Source: https://stackify.com/guide-docker-java/
Posted by: martinsumessneve.blogspot.com

0 Response to "How To Install Java On Docker Container"
Post a Comment