Tuesday 5 July 2016

Docker images creation in a development environment

Summary


Sorry, It´s been a while since my last post, a mixture of not having anything worth writing, holidays and some online training that drains most of my time.
Here is something I would like to share that might reduce the pain for those who want to dockerize their Spring-Boot applications (or any Java application) and then test and tune them while running inside a Docker container.

Former setup

  • A commit was pushed to Jenkins, who compiled and unit-tested it.
  • After some code analysis, a Docker image was created and pushed to a repository
    With set-up, testing was highly inefficient.
  • To test it in a server, I had to pull it and execute it and, while I was focused in the performance and memory consumption of my application, tuning the JVM parameters was essential... Unfortunately, they were given at compilation time (a Maven plugin) and could not be changed (or I did not know how to).
The drawbacks I see of this approach:
  • It was slow to test new changes, as the whole CI flow needed to be executed.
  • Unnecessary docker-related commits to the branch generating the Docker images.
The solution I found? Building the image myself before testing it.

Building your images with Docker Compose


This setup makes the try-an-error cycle much faster while allowing higher degree of customization, depending on the target environment:


In this leaner flow, you build the image in situ.


What do you need for this? Just three simple text files


Create a docker-compose file with your environment-specific requirements

Here, we have replaced the reference to the image built by our CI system and instead we will build it ourselves. The Java application will take the parameters we give it in this file, allowing fast try-and-test cycles.

Add a Dockerfile

WARNING: Pay attention to the Unix/Windows end-line characters unless you want to spend a couple of days chasing ghosts!


Add an entry-point script

As you can see, there are several options for retrieving the JAR file that will be executed:
  • From a local compilation: Very convenient if you are performing changes in the code and you want to see the effect right away.
  • From a CI agent/repository: If, on the other hand, you are more focused in tuning a previously generated Jar file (memory settings, monitoring and so on.
You can easily configure this using an external environment file (.env) holding the path the binary file:


What are the advantages of doing this?

  • You can modify in which way you want to invoke your application without having to modify anything but the docker-compose file.
  • The Dockerfile and entry-point.sh script are totally generic and can be reused in other modules.


How to build the image and run the container:

Just place the three files you wrote together (or even better, if you are reusing the Dockerfile and entrypoint.sh just use their paths) and execute these commands:

docker-compose build --no-cache

Once your image has been built, launch your services as usual:

docker-compose up -d

Your service will be up and running and you can test your configuration changes right away!

Anyway, I am still struggling to get this right, specially that I intend to use Docker Swarm to launch my services in a cluster.

How do you tackle this sort of problems with the images generated by your CI system? Do you use other approaches? Feel free to share your thoughts and hopefully we all can learn from them!

No comments:

Post a Comment