How to Automate Docker Container Deployment with Maven
Containerization using Docker has revolutionized application development and deployment over the past few years. However, it also introduces many new complexities. Adopting Docker requires significant organizational and process changes. Developers struggle with a steep learning curve understanding containers. Many teams attempting to containerize applications find themselves managing a tangled mess of container build, deployment and management scripts.
This is where integrating Docker with Maven comes in. Maven is the most popular dependency management and build automation tool within Java ecosystem. Over 70% of Java developers use Maven as part of their toolchain. Automating container builds within the Maven process provides a cleaner way to adopt Docker without disrupting established development flows.
This guide aims to equip Java developers who are familiar with Maven to start automating Docker deployments. We will walk through a step-by-step example. The goal is to demonstrate an effective, real-world approach conforming to best practices for integrating Docker containerization into Maven-based build pipelines.
The Case for Containers
Let‘s first briefly discuss the appeal of Docker and containers.
Modern applications are increasingly deployed as distributed, cloud-native microservices architectures. This enables much needed agility and velocity within IT organizations. However, it also imposes massive complexity. Developers struggle with dependency conflicts, environment inconsistencies and configuration drift across many services deployed to diverse runtimes.
The following statistics highlight the scale of the problem:
- 70% of companies are either using or evaluating containers according to RightScale
- 80% of organizations utilizing microservices face frequent environment issues
- 65% of developer time wasted due to configuration issues across environments
Containers encapsulate applications together with their entire runtime environment into isolated processes. This provides predictable, reliable and portable deployments. Containers stand up quickly and apply changes consistently across deployments:
However, organizations can realize these benefits only if they effectively adopt containerization across their infrastructure. And this requires overcoming cultural and technological barriers.
Surveys indicate the top challenges with container adoption:
- Struggling with organizational changes needed (62%)
- Lack of container skills within teams (68%)
- Manual container deployments (73%)
The reality is most developers find adopting Docker difficult. It often ends up becoming just another piece of tooling instead of an integral part of deployments. Developers wrestle with low-level Docker commands, scripts and custom infrastructure instead of focusing on application code.
Automating container builds within existing development toolchains helps overcome these adoption challenges.
Why Docker and Maven?
Docker has clearly emerged as the industry standard tool for containerization. Other complementary technologies like Kubernetes later provide orchestration and management at scale.
Maven dominates the Java world when it comes to build automation and dependency management. Here are some key statistics:
- Over 70% of Java developers use Maven
- 86% claiming higher productivity with Maven over other build tools
- 800% increase in Maven Central downloads over last decade
Integrating Maven with Docker allows harnessing both technologies more effectively:
1. No context switching between tools
Developers can build and deploy Docker containers without leaving the familiar Maven toolchain. They avoid switching between separate scripts or command line interfaces during development.
2. Consistent containerization pipeline
Image building can be codified as part of the existing Maven continuous integration process enabling reliable flows from dev through to production.
3. Standardized process across teams
Placing container configuration within the Maven pom.xml
imposes consistent conventions. This simplifies onboarding and knowledge sharing across developer teams.
4. Simpler path to container adoption
Packaging applications as containers becomes just another standard phase rather than a separate hurdle in the development toolchain.
Now that we have motivated the value proposition of integrating Docker and Maven, let‘s look at a step-by-step example.
Sample App Overview
To illustrate an effective real-world workflow, we will containerize a Java web application using Maven and Docker.
The application displays a simple responsive homepage with greeting messages. It leverages Spring Boot for the middleware framework and Bootstrap for front-end styling.
The page dynamically loads random greetings from an API endpoint:
The project build and dependencies are managed by Maven. Out of the box, developers would execute mvn package
to produce a Java archive which can be deployed to stand-alone Tomcat or Jetty servers.
We will enhance this setup to build Docker images as part of the Maven packaging phase. Let‘s get started!
Step 1 – Install Prerequisites
You will need the following installed to follow along with the examples:
- OpenJDK 8+ JDK
- Apache Maven 3.6+
- Docker Engine 19+
- Git client
- IDE or editor of choice
Step 2 – Clone Sample App GitHub Repository
Let‘s clone the sample web app repository which has the starting point code:
git clone https://github.com/TestUser/docker-maven-demo.git
cd docker-maven-demo
The pom.xml file is configured for Spring Boot and the project builds a deployable JAR file by default.
Step 3 – Define Docker Image with Dockerfile
We need to describe how to package the application as a Docker image by creating a new Dockerfile:
# Start from base Java image
FROM adoptopenjdk/openjdk11:jre-11.0.15_1
# Add Author Info
LABEL maintainer="TestUser"
# Copy generated jar
COPY target/*.jar app.jar
# Run the jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
This Dockerfile:
- Uses AdoptOpenJDK 11 as parent image
- Sets the maintainer label
- Copies the Jar build artifact
- Configures entry point to launch the application
When complete, the Maven build will produce a Docker image instead of just the deployable Jar file.
Step 4 – Copy Docker Resources
We now update pom.xml to copy Dockerfile and other assets into the Maven target directory:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-docker-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>src/main/docker</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
This copies Dockerfile as well as other configuration files into target ready for Docker image build.
Step 5 – Invoke Docker Build and Tag Image
Next, we will utilize maven-antrun-plugin to directly call Docker commands to build and tag image:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<exec executable="docker">
<arg value="build"/>
<arg value="-t"/>
<arg value="${project.artifactId}:${project.version}"/>
<arg value="target"/>
</exec>
</target>
</configuration>
</execution>
</executions>
</plugin>
This executes docker build
as part of the Maven package phase. The image is tagged with artifact ID and version defined in pom.xml.
Step 6 – Push Image to Docker Registry
For distributing the image to other teams, we should push it to a registry. DockerHub is the default public registry to host Docker images.
First, let‘s configure Maven to authenticate with our Docker ID:
<properties>
<docker.username>testuser</docker.username>
<docker.password>pa55w0rd!</docker.password>
</properties>
<servers>
<server>
<id>docker-hub</id>
<username>${docker.username}</username>
<password>${docker.password}</password>
</server>
</servers>
Next, we add the push command by updating maven-antrun-plugin:
<exec executable="docker">
<arg value="tag"/>
<arg value="${project.artifactId}:${project.version}"/>
<arg value="docker.io/${docker.username}/${project.artifactId}:latest"/>
</exec>
<exec executable="docker">
<arg value="push"/>
<arg value="docker.io/${docker.username}/${project.artifactId}:latest"/>
</exec>
We now have a complete automated Docker image build pipeline integrated with Maven!
Step 7 – Build and Run Container
With above configuration in place, we can run:
mvn clean package
This will first compile Java classes, then build the Docker image and push it to DockerHub.
To launch the published containerized application locally:
docker run -p 8080:8080 testuser/docker-maven-demo:latest
The application will be accessible on http://localhost:8080.
Automating the entire pipeline through Maven allows simplified adoption without disrupting existing development flows.
Advanced Customizations
There are many options for further customizing and extending this automated Docker setup through Maven.
Parameterizing Configurations
We can externalize container configurations, tags, registry URLs etc. into pom.xml properties. These can then be overridden via Maven command line arguments or environment variables.
For example:
<properties>
<container.tag>latest</container.tag>
</properties>
<docker.image>myregistry.com/${project.artifactId}:${container.tag}</docker.image>
Build with:
mvn package -Dcontainer.tag=release-2.3
Setup for Different Environments
Separate Maven profiles can define custom configurations for each environment:
<profiles>
<profile>
<id>development</id>
<properties>
<docker.registry>dev-docker-registry</docker.registry>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<docker.registry>prod-docker-registry</docker.registry>
</properties>
</profile>
</profiles>
<docker.registry>${docker.registry}</docker.registry>
Now build images with:
mvn package -P production
Similarly, we can also have granular control over environment variables, configuration secrets etc.
Integration with CI/CD Pipelines
There are Maven plugins available for integrating with most leading DevOps pipelines tools:
These plugins enable setting up continuous build of Docker images on code commits or automated deployments when tests pass.
Container Registry Authentication
Instead of hardcoding Docker authentication, utilize Maven‘s encrypted password storage. Create secure server credentials:
mvn --encrypt-password mypassword
{lR9zaidavNLxm74Ec7M3JGz1TLqdBjJupvkZyBm9+yQ=}
Configure encrypted passwords within pom.xml:
<servers>
<server>
<id>docker-registry</id>
<username>testuser<username>
<password>{lR9zaidavNLxm74Ec7M3JGz1TLqdBjJupvkZyBm9+yQ=}</password>
</server>
</servers>
Zero-Downtime Deployments
For mission critical systems, utilize Docker healthchecks, multiple replicas etc. to avoid application downtime while redeploying containers:
There are open source tools like Fabric8 that integrate well with Maven for enabling advanced container deployments.
Container Orchestration and Management
As an organization scales to hundreds of container instances across many hosts, Kubernetes becomes vital for lifecycle management.
The Kubernetes Maven plugin allows deploying Docker images built through Maven onto a Kubernetes cluster. Use alongside CI/CD systems for complete end-to-end automation.
Conclusion
In this comprehensive guide, we walked through containerizing a sample Java application using Maven and Docker – including building images and pushing to an registry.
Key highlights:
- Motivation for adopting Docker containers and microservices
- Overview of Maven and Docker platform statistics
- Step-by-step tutorial containerizing a Java web application
- Detailed configurations for automating build pipeline with Maven
- Options for customization and production deployments
Maven and Docker both provide immense value individually. Integrating them unlocks even more potential. It paves a gradual adoption path for developers by fitting containers within existing toolchain.
If you found this guide useful, do check out my other articles on Docker, Kubernetes and cloud-native technologies. Let me know what else you would like to see covered!