How to build application image with Dockerfile?
- Natan Ferreira
- 0
- 104
Since this is a Java application, I need to use an image that can run a Java application. We need the Dockerfile and to use the OpenJDK base image.
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar /app/api.jar
EXPOSE 8080
CMD ["java", "-jar", "api.jar"]
This Dockerfile is a recipe for building a Docker image that runs a Java application. Each instruction in the Dockerfile has a specific purpose. Let’s go through it line by line:
FROM eclipse-temurin:17-jre-alpine
- This line defines the base image for the container, which will be
eclipse-temurin:17-jre-alpine
. eclipse-temurin
is an image based on the OpenJDK Java Runtime Environment (JRE), distributed by the Eclipse Foundation. This image provides the necessary Java infrastructure to run applications.- The
17-jre-alpine
version indicates that we’re using JRE version 17 (Java 17).
WORKDIR /app
- Sets the working directory as
/app
within the container. - All subsequent commands will be executed within this directory, and any files copied or created will be placed inside it.
- Setting the
WORKDIR
helps maintain organized file structure within the container.
COPY target/*.jar /app/api.jar
- Copies the
.jar
file from the local system’starget
folder to the container, renaming it asapi.jar
. - This
.jar
file is the artifact generated by the application’s build, containing all the code necessary for execution. - Since the
.jar
file name can vary, the Dockerfile uses a wildcard*.jar
to capture any.jar
file within thetarget
folder.
EXPOSE 8080
- Informs that the application inside the container will listen on port 8080. This line by itself does not open the port but serves to document and assist in mapping the correct port when running the container.
- During execution (
docker run
), this port can be exposed to the host, for instance, by using-p 8080:8080
to allow external access.
CMD ["java", "-jar", "api.jar"]
- Specifies the command that will be executed when the container starts. In this case, the command is:
java -jar api.jar
- This command starts the Java application by running the previously copied
api.jar
file.
To create a Docker image with the Dockerfile, you can use the following command:
docker image build -t company .
The docker image build
instructs Docker to build an image.
The -t company
allows you to name the image, where “company” is the image name. Since no version is specified, Docker will use “latest” by default, meaning that tag will be named latest
.
In this case, .
indicates the current directory, where the Dockerfile is expected to be located.
Thus, the image is generated using the Dockerfile that was created.
It is necessary to have the .jar file in the target folder. If it doesn’t exist, simply run the following command:
clean package
Result of the image creation when running the command.
To run a container from the created image, simply execute the following docker command:
docker container run --rm -p 8080:8080 company
It will run a container from the company image on port 8080.
The -rm
indicates that after stopping the container, it will be automatically removed.
You will likely encounter a scenario where you need to communicate with another container, such as a database container. The application container needs to connect to the database container. Let’s try this scenario using everything we’ve covered so far.
Let’s create a MySQL container for the application, as it is the database I am using.
docker container run -d -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --name company-mysql mysql:8.0.39
Now we can run the application again.
docker container run --rm -p 8080:8080 company
We have the following error:
We couldn’t connect to the database, but why?
This happens because the application container and the database container are on different networks. We need to place both on the same network in order to connect successfully. To resolve this, we first need to create a network.
docker network create --driver bridge company-network
Removing the previously created MySQL container.
docker container rm company-mysql --force --volumes
Creating a MySQL container on the created network.
docker container run -d -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --network company-network --name company-mysql mysql:8.0.39
Another important thing we must do is parameterize the MySQL connection in the application. In the properties file, where we specify the database host, we cannot leave it fixed as localhost, so I made the following adjustment.
spring.datasource.url=jdbc:mysql://${DATABASE_HOST:localhost}/company?createDatabaseIfNotExist=true&serverTimezone=UTC
If no host value is provided as a parameter, localhost will be used by default.
I will generate a new JAR file to recreate the image.
mvn package
docker image build -t company .
Now, when running the container, we will specify the network and the MySQL database host. Don’t forget to check if the MySQL container is running.
docker container run --rm -p 8080:8080 -e DATABASE_HOST=company-mysql --network company-network company
Now the containers can communicate with each other and we no longer have problems connecting the API to the database, as both are on the same network.
Author
-
Hello there, I’m Natan Lara Ferreira, Full Stack Developer Java and Angular since 2016. I’m in Open Finance Brazil project using framework Quarkus and Angular since the beginning 2021. I'm a problem solver, critical thinker and team player.