How to Dockerize an Application and Prepare It for Deployment
Modern software development increasingly relies on containerization to ensure applications run consistently across environments. Docker makes it possible to package an application together with its dependencies, runtime, and configuration into a portable unit that can run anywhere Docker is supported. In this article, we will build a simple REST service, package it using Docker with an Eclipse GlassFish base image, and walk through the process of building, testing, and preparing the container for deployment.
1. What is Docker?
Docker is an open-source platform that allows developers to build, package, and run applications inside containers. Instead of installing software and dependencies directly on the host system, Docker packages everything required to run the application into a container image that can be executed consistently across development, testing, and production environments.
Docker works by using lightweight virtualization through container technology. Unlike traditional virtual machines that require a full operating system, Docker containers share the host OS kernel while isolating the application environment. This makes containers faster to start, more efficient, and easier to distribute.
2. What is a Containerized Application?
A containerized application is an application that has been packaged together with its runtime environment, libraries, configuration files, and dependencies inside a container image. This container image can be executed on any system that has a container runtime such as Docker installed.
The key advantage of containerized applications is consistency. We no longer need to worry about differences between environments such as operating systems, installed libraries, or server configurations. Once the application is containerized, it will behave the same way whether it runs on a our machine, a staging server, or a production cluster.
3. Creating a Sample REST Service
Before Dockerizing the application, we first need a simple REST service. This example uses Jakarta REST (formerly JAX-RS) to create a REST endpoint that returns a simple message. The application will be packaged as a WAR file and deployed to GlassFish inside a Docker container.
This example project follows the standard Maven directory structure used for Java web applications. The Java source files are located under src/main/java, while the deployment descriptor resides in the WEB-INF directory. When built with Maven, the project produces a WAR file that can be deployed to a Jakarta EE application server such as GlassFish.
Creating the REST Endpoint
Below is the REST resource class that will handle HTTP requests.
@Path("/hello")
public class HelloResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from a Dockerized Jakarta EE application!";
}
}
This class defines a simple REST endpoint using Jakarta REST annotations. The @Path("/hello") annotation maps the endpoint path, while @GET specifies that the method handles HTTP GET requests. The method returns a plain-text response confirming that the service is running.
4. Writing the Dockerfile
The Dockerfile contains the instructions Docker uses to build an image. It defines the base runtime environment, copies application files into the container, configures ports, and specifies how the container starts. In this article example, we use a GlassFish base image and copy the compiled WAR file into the server’s autodeploy directory so it is automatically deployed when the container starts.
Dockerfile
FROM ghcr.io/eclipse-ee4j/glassfish:8.0.0 COPY target/jakartaee-docker-app.war /opt/gfinstall/glassfish/domains/domain1/autodeploy/ EXPOSE 8080 4848 CMD ["asadmin", "start-domain", "-v"]
This Dockerfile starts from a GlassFish base image that already includes a configured Jakarta EE server. The COPY instruction moves the compiled WAR file into the autodeploy directory so GlassFish deploys it automatically when the container starts. The EXPOSE instruction indicates the application will be accessible through port 8080, and the CMD instruction launches the GlassFish domain.
Handling Environment Variables
Environment variables provide a flexible way to configure containerized applications without modifying the application code. They are commonly used to define settings such as application ports, database connections, file paths, and environment-specific configurations.
In Docker, environment variables can be defined in a Dockerfile using the ENV instruction or passed when running a container. Using variables instead of hardcoded values makes Docker images easier to maintain and reuse across development, testing, and production environments, since configuration values can be updated in one place and referenced throughout the Dockerfile.
For example, if the installation directory of an application server changes, only the environment variable needs to be updated instead of modifying multiple file paths throughout the configuration.
Dockerfile Example Using Environment Variables
FROM ghcr.io/eclipse-ee4j/glassfish:8.0.0 ENV GLASSFISH_HOME=/opt/gfinstall ENV GLASSFISH_LIB=$GLASSFISH_HOME/glassfish/domains/domain1/lib/ COPY libs/mysql-connector-j-9.2.0.jar $GLASSFISH_LIB/ COPY target/jakartaee-docker-app.war $GLASSFISH_HOME/glassfish/domains/domain1/autodeploy/ EXPOSE 8080 4848 CMD ["asadmin", "start-domain", "-v"]
In this configuration, the ENV instruction is used to define reusable variables for the GlassFish server installation. The GLASSFISH_HOME variable represents the base directory where GlassFish is installed inside the container. Defining this path as an environment variable helps avoid repeating the full directory path in multiple instructions.
The GLASSFISH_LIB variable builds on the first variable and points to the lib directory of the GlassFish domain. This directory is where shared libraries such as JDBC drivers can be placed so they are available to all deployed applications. In the above example, the MySQL Connector/J driver is copied into this directory using the COPY instruction. Because the library path is defined using an environment variable, the Dockerfile remains clean and easier to modify if the server path changes later.
Running a Container with Environment Variables
Environment variables can also be passed when starting a container. This allows runtime configuration values such as passwords or server settings to be supplied dynamically rather than stored inside the Docker image.
For example, the GlassFish container supports the AS_ADMIN_PASSWORD environment variable for configuring administrative credentials.
docker run -p 4848:4848 -p 8080:8080 -e AS_ADMIN_PASSWORD=javacodegeeks ghcr.io/eclipse-ee4j/glassfish
In this command, the -e flag is used to define an environment variable at runtime. The AS_ADMIN_PASSWORD variable sets the administrator password used to access the GlassFish administration console.
Using environment variables in this way allows sensitive configuration values such as passwords to be provided during container startup instead of being embedded directly inside the Dockerfile or application code.
5. Building the Docker Image
After writing the Dockerfile, we can build the Docker image that contains the application and the server runtime.
First, build the application with Maven:
mvn clean package
Next, build the Docker image:
docker build -t jakartaee-docker-app .
The Maven command compiles the application and produces the WAR file in the target directory. The Docker build command reads the Dockerfile and packages the application together with the GlassFish runtime into a Docker image.
6. Testing the Container Locally
Before deploying the image, it is important to verify that the container runs correctly.
Run the Container
docker run -p 8080:8080 -p 4848:4848 jakartaee-docker-app
This command starts a new container from the built image. The -p 8080:8080 option maps the container’s port 8080 to the host machine so the application can be accessed from a browser or HTTP client.
Test the Endpoint
http://localhost:8080/jakartaee-docker-app/api/hello
Expected output:
Hello from a Dockerized Jakarta EE application!
If this response appears, it confirms that the container started successfully and the application deployed correctly inside the GlassFish server.
7. Preparing the Image for Deployment
After confirming that the container runs correctly locally, the next step is to prepare the Docker image for deployment. A common approach is to upload the image to a container registry so it can be accessed by other systems such as CI/CD pipelines, cloud platforms, or orchestration tools like Kubernetes. In this example, we will use Docker Hub as the registry to store and distribute the image.
Before pushing the image, you need a Docker Hub account. Create an account on Docker Hub and then authenticate your local Docker client using the docker login command. This step connects your terminal to your Docker Hub account so you can push images to your repositories.
Authenticate with Docker Hub
docker login
When you run this command, Docker will prompt you to enter your Docker Hub username and password. Once authenticated, your terminal session will be authorized to push images to your Docker Hub repositories.
Tag the Image
Before pushing the image, it must be tagged with your Docker Hub username and repository name.
docker tag jakartaee-docker-app your-dockerhub-username/jakartaee-docker-app:1.0
This command creates a new tag for the image that follows the Docker Hub naming convention. The tag includes your username, the repository name, and the version of the image.
Push the Image
docker push your-dockerhub-username/jakartaee-docker-app:1.0
The docker push command uploads the image to your Docker Hub repository. Once the upload is complete, the image can be pulled and used from any system that has access to Docker Hub.
Publishing images to a container registry like Docker Hub makes it easier to distribute and deploy applications across different environments, ensuring that the same container image is used consistently in development, testing, and production.
8. Conclusion
In this article, we explored how to Dockerize a Jakarta EE application and prepare it for deployment. We started by understanding what Docker is and what a containerized application means. Then we built a simple REST service, wrote a Dockerfile using the Eclipse GlassFish base image, built the Docker image, and tested the container locally.
Finally, we prepared the image for deployment by tagging and pushing it to a container registry. Containerizing applications with Docker helps ensure consistent environments, simplifies deployment workflows, and makes modern cloud-native development much easier.
9. Download the Source Code
This article explained how to containerize your application with Docker and deploy it.
You can download the full source code of this example here: how to dockerize your application and deploy it







