Create optimized docker images for spring boot

We can build a container easily for spring boot application by writing a simple dockerfile, but in this typical approach our docker container is not optimized. Even in my previous article on dockerizing  the spring boot app and redis is not optimized, we can optimize the docker container by layering the docker image.  


- Docker
- Java 8 or higher
- Spring boot 2.3.0 or higher 
- Maven 3.6.3 or higher

For the ease of explanation I'm using a tool called dive to inspect the docker image. You can install it by referring to below link.

I'm using my rest-api-localization project to demo the optimized docker images.

1) Basic Dockerfile

Drawback of using above docker file is our application is building as single flat jar (application code + dependencies) and every time for minor code change the entire layer is rebuilding. This will take up both time and disk space.

Let's build the docker image and inspect, to build the docker image run 
 docker build -t rest-localization:v1 .  
Lets inspect the build image using dive tool, run 
 dive {image}
eg: dive c9ebdadb38f4
As per the dive output our jar file is 19MB in size which is pretty big since its a flat jar with application code plus dependencies. Lets compare the jar size after we optimize our container in the next section.
2) Optimized Dockerfile 
To optimize the docker image we are going to split the application into multiple layers in the docker image. In the above image least frequently changed layers are at the bottom. Docker use cache to reuse these layers when building and no need to rebuild them again, this will save build time for us. Lets have a look at the docker file. 
- In this docker file we have use a builder to combined our result from first phase (layering the jar and extracting) to the next phase. You can learn more about builder in this post.
- jarmode=layertools is used to extract the jar in to layers. 
- These layers are defined in BOOT-INF/layers.idx inside the jar file.
- The application will be run using the JarLanucher.
- Let's build the docker image again and inspect it using dive.
- Now you can see it's layered, the last layer is the application layer, now only 9.3 KB which is quite small and only contain your code, every time you made a code change only this last layer will be build.
- To make sure our application is working run the docker image we build and execute the curl.
docker run -d -p 8080:8080 rest-localization:v1
curl -X GET -H "Accept-Language: zh" 'http://localhost:8080/api/v1/menu'

That's it for this post, as usual source code can be found in 

In the next post I will share how to create a container images without creating docker files using Cloud Native BuildPacks. Thank you for reading please share your comments and ideas. 

References & Useful Readings.