Spring Boot and Docker

Summary

My toy angular/rest/spring project, HIIT (high intensity interval training), was something I wanted to package inside a docker container that could run on any machine, regardless of the presence of a JVM (especially Java8). I decided to try out the maven targets for packaging in a docker image – the result was VERY easy to do.

Background

Docker is something I’ve been slow to warm to. Historically my argument against it is that it was a quick-and-dirty solution (and I felt dirtier than it has to be) vs. standard package management like rpm/deb files. However, as I’ve played with Docker more seriously and thought about the troubles it digs people out of I’ve changed my tune. Pros that docker brings include not worrying about the dependencies that make your app run (i.e. the jvm) and being able to allow parameters/shared volumes to run multiple containers side-by-side with nearly zero overhead. When comparing this to standard package management this just isn’t possible.

My friend Blake also said something to me that really resonated, he said think of a docker image as your application’s “executable”. This instantly clicked with me. An executable is something that can be adjusted with command-line switches and is fully self contained (let’s not get too pedantic about dynamic libraries). It’s can be run many times and the switches give it a different ‘profile’. Once I started thinking about Docker images this way, it made me want to do more with Docker since it gives so much flexibility AND given its immutable nature (i.e. an image can never be changed, it is frozen in time just as git freezes a repo in time at each commit) Docker allows multiple instances to be running quite easily and unaware of each other.

How To

The Spring Blogs given a good Docker tutorial, all I did was apply the tutorial to my app.

First

First I made sure docker was installed on my machine (Ubuntu 15.10). This was as simple as running apt-get

sudo apt-get install docker

Second

After docker was installed I proceeded to add details to my pom.xml. You can see my branch here where I have the Dockerfile and changes in the pom.xml. There’s some other noise with my update of Spring Boot in the same branch, but generally speaking the interesting changes are

Dockerfile

FROM java:8
VOLUME /tmp
ADD com.basilio.hiit-0.0.1-SNAPSHOT.jar hiit.jar
RUN bash -c 'touch /hiit.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-Dspring.profiles.active=hsqldb","-jar","/hiit.jar"]

pom.xml

..
<properties>
  <docker.image.prefix>jimbasilio</docker.image.prefix>
</properties>
..
<!-- Package as a docker image -->
<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.2.3</version>
    <configuration>
        <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
        <dockerDirectory>src/main/docker</dockerDirectory>
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
    </configuration>
</plugin>

The Dockerfile grabs the java:8 docker image from the docker repo, creates a shared volume in /tmp (where tomcat will write to), ensures the jarfile has a fresh datestamp on a docker rebuild, and declares the entrypoint to run (which means what switches I want the docker “exe” to automatically use). You can see I wanted to run in the -Dspring.profiles.active=hsqldb profile but I could have also passed parameters into docker to set the active profile.

Third

Now when I issue the docker image build via maven

[jim@galago~/projects/HIIT (master)]$ mvn package docker:build

you can see the docker image being built. From here I can see my image and then run my image and start my container

[jim@galago~/projects/HIIT (master)]$ sudo docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
jimbasilio/com.basilio.hiit   latest              c3360feee95d        2 minutes ago       714.1 MB
java                          8                   d4849089125b        3 weeks ago         642 MB
[jim@galago~/projects/HIIT (master)]$ sudo docker run -p 8080:8080 jimbasilio/com.basilio.hiit
....loads of spring boot stuff printed to stdout to let you know what's going on

Now, point your browser to http://localhost:8080 you’ll see the hiit app (in all its skeleton glory) show up. Also, notice the console out messages being emitted from the docker container that’s being executed.

I can also run another container on port 8081 and it will happily startup

[jim@galago~/projects/HIIT (master)]$ sudo docker run -p 8081:8080 jimbasilio/com.basilio.hiit

Now point your browser to http://localhost:8081, you’ll see console message from hits to that port. The cool thing is the Spring Boot application has no idea it’s serving on port 8081, because it’s really bound to the docker container’s port 8080. At this point I could go more advanced and put a load balancer in front of both port 8080 and 8081 and optimally flood my CPUs (although realistically on 1 machine java will already do this quite happily by threaded connections through Tomcat).

Bottom Line

Docker is something that takes some getting used to. Thinking about the final Docker image as an ‘executable’ AND also an immutable (and comprised of) series of inner containers with each building on the previous immutable image helps things (at least it will help things once they start to click).

Being able to spin-up your ‘exe’ wherever you are (think dumb cloud box), not having to worry about what the host system has installed, and the very low overhead that containers have gives you one more tool in the toolbox to manage your application.

More examples of Docker usage are a maven docker image so you don’t have to worry about your CI builds (i.e. Jenkins) having maven installed. You can simply  have Jenkins start the maven docker container, share a volume with your sourcecode, compile/run tests, then the stdout is checked for success.

Docker is an endless thought experiment which really opens a lot of doors for creative (and reproducible) solutions.

Good luck and ENJOY!

Spring Async is so easy! (once you know the tricks…)

All source code under my github account.

Summary

Spring Async is designed to make threads easy to implement. It was introduced in Spring 3.0 intending to make Future easier to use as an annotation on Components (since then, CompletableFuture<T> has been introduced in Java8 and adds a ‘promise’-like framework, a topic for another blog). The key to using it correctly is realizing you MUST create your @Async annotated classes in another (Spring component) class so Spring can proxy it. More info below…

Background

A little background (with as much depth as I can provide without hopefully going beyond what I know as truth). At its core Spring is a Dependency Injection (DI) container. You may know this already, I did too and still fell into this @Async trap. In addition to a DI container, Spring also has lots of magic with instrumentation, AKA Aspects. When you annotate something in Spring (ex. @Async) what you are actually doing is telling Spring “when you load this class, you should apply AOP as methods are invoked” (i.e. points that Spring will invoke prior/after to invoking the function itself).

If you look at the spring example for @Async you’ll see that it requires you to put your @Async methods in a new spring bean, you CANNOT annotate local functions and invoke them and see any new threads created.

Creating a local instance of the FacebookLookupService class does NOT allow the findPage method to run asynchronously. It must be created inside a @Configuration class or picked up by @ComponentScan.

Back to the point

So given the above, it becomes more obvious (hopefully) why the @Async annotation needs to be present, because if it’s not Spring can’t wrap the calls prior/after to the function in order to create all the wrappers necessary to run your code through the boilerplate code in spring.

The hard way

(coming)

The easy way

First we need to turn on our @Async notations.

  1. @SpringBootApplication
  2. @EnableAsync
  3. public class SpringAsyncApplication {
  4.  
  5.     public static void main(String[] args) {
  6.         SpringApplication.run(SpringAsyncApplication.class, args);
  7.     }
  8.  
  9. }

Then we need to create a new spring component (in this case an @Service) so that spring can wrap things correctly:

  1. @Service
  2. public class AsyncService {
  3.  
  4.     @Async
  5.     public Future doFoo(String someArgument)
  6.             throws InterruptedException {
  7.         System.out.println("about to start Foo service (good async)");
  8.         Thread.sleep(3000);
  9.         System.out.println("finishing Foo service (good async)");
  10.  
  11.         return new AsyncResult(
  12.                 "Congrats. You finished a real thread from Foo Service (good async)");
  13.     }
  14.  
  15.     @Async
  16.     public Future doBar(String someArgument)
  17.             throws InterruptedException {
  18.         System.out.println("about to start Bar service (good async)");
  19.         Thread.sleep(3000);
  20.         System.out.println("finishing Bar service (good async)");
  21.  
  22.         return new AsyncResult(
  23.                 "Congrats. You finished a real thread from Bar Service (good async)");
  24.     }
  25. }

The output of our application shows things executing in parallel

[jim@galago~/projects/SpringAsync (master)]$ mvn clean package
...
[jim@galago~/projects/SpringAsync (master)]$ java -Dspring.profiles.active=goodasync -jar target/async-0.0.1-SNAPSHOT.jar
...
Starting up REAL async services.
Took 3 ms to start threads.
about to start Foo service (good async)
about to start Bar service (good async)
finishing Foo service (good async)
finishing Bar service (good async)
Foo done in 3018 ms.
Bar done in 3018 ms.
Total time ellapsed 3018 ms.

It took approximately 3s to execute both threads in parallel. If this were serially executed we would have seen things finish in over 6s (see ‘the wrong way’)

The wrong way

In this example we annotated local functions with @Async …. and things execute serially:

  1. @Component
  2. public class MyRunner implements CommandLineRunner {
  3.     @Autowired
  4.     private AsyncService realAsyncService;
  5.  
  6.     @Value("${app.goodasync:false}")
  7.     private boolean isGoodAsync;
  8.  
  9.     @Override
  10.     public void run(String... args) throws Exception {
  11.         Future fooService;
  12.         Future barService;
  13.  
  14.         StopWatch swOverall = new StopWatch();
  15.         swOverall.start("overall");
  16.  
  17.         StopWatch sw = new StopWatch();
  18.         sw.start();
  19.  
  20.         if (isGoodAsync) {
  21.             // call async methods through service call
  22.             System.out.println("Starting up REAL async services.");
  23.             fooService = this.realAsyncService.doFoo("an argument");
  24.             barService = this.realAsyncService.doBar("another argument");
  25.         } else {
  26.             System.out.println("Starting up BROKEN async services.");
  27.             fooService = this.doFoo("an argument");
  28.             barService = this.doBar("another argument");
  29.         }
  30.  
  31.         sw.stop();
  32.         System.out.println(
  33.                 "Took " + sw.getTotalTimeMillis() + " ms to start threads.");
  34.  
  35.         sw.start();
  36.         fooService.get();
  37.         sw.stop();
  38.         System.out.println("Foo done in " + sw.getTotalTimeMillis() + " ms.");
  39.  
  40.         sw.start();
  41.         barService.get();
  42.         sw.stop();
  43.         System.out.println("Bar done in " + sw.getTotalTimeMillis() + " ms.");
  44.  
  45.         swOverall.stop();
  46.         System.out.println("Total time ellapsed "
  47.                 + swOverall.getTotalTimeMillis() + " ms.");
  48.     }
  49.  
  50.     @Async
  51.     public Future doFoo(String someArgument)
  52.             throws InterruptedException {
  53.         System.out.println("about to start Foo service (broken async)");
  54.         Thread.sleep(3000);
  55.         System.out.println("finishing Foo service (broken async)");
  56.  
  57.         return new AsyncResult(
  58.                 "You finished a broken thread from Foo Service (broken async)");
  59.     }
  60.  
  61.     @Async
  62.     public Future doBar(String someArgument)
  63.             throws InterruptedException {
  64.         System.out.println("about to start Bar service (broken async)");
  65.         Thread.sleep(3000);
  66.         System.out.println("finishing Bar service (broken async)");
  67.  
  68.         return new AsyncResult(
  69.                 "You finished a broken thread from Bar Service (broken async)");
  70.     }
  71.  
  72. }

We expect that we will see execution time serially occurring, meaning in 6s

[jim@galago~/projects/SpringAsync (master)]$ mvn clean package
...
[jim@galago~/projects/SpringAsync (master)]$ java -Dspring.profiles.active=badasync -jar target/async-0.0.1-SNAPSHOT.jar 
...
Starting up BROKEN async services.
about to start Foo service (broken async)
finishing Foo service (broken async)
about to start Bar service (broken async)
finishing Bar service (broken async)
Took 6002 ms to start threads.
Foo done in 6002 ms.
Bar done in 6002 ms.
Total time ellapsed 6004 ms.

And this is exactly what we see…

Bottom Line

Spring is such a useful framework because it captures boilerplate code in a useful manner to save you time developing AND to save you bugs in what is normally foundational code. You shouldn’t feel you MUST use Spring for everything, but if it solves your problem it will likely save you bugs you may have written. Threaded code is ESPECIALLY nasty when you miss something.

For me, once I realized my @Async code needed to be in a separate @Bean/@Service/etc I was able to benefit from Spring’s logic.

Thanks for reading!

Spring boot (profiles)

Background

I’m pretty new to the spring ‘scene’.  I did Java work out of college for quite awhile, even working on J++ (anyone remember that?) for a few years until moving companies and transitioning to C#/.net for a full 10 years.  I’ve always been interested and motivated by the open source community and the work that goes into these projects, but .net hasn’t historically lent itself to this community (I do have to say, MS does seem to be changing things a little bit here recently).

However, this all changed at the end of 2013.  I was (luckily) involved in a project at work that utilized Spring to reboot our group to have more java in the mix.  Alongside java was linux as the development environment.

The Experience

Just like with any new technology stack, spring felt fairly overwhelming.  The java world had matured a LOT since I was last involved with it – spring was very deep and pretty confusing, but I could see that the spring team was solving very common enterprise problems with very strong design patterns.  I WANTED to learn more about spring, I WANTED to learn more about Java and the current state of the language.

What followed was a few months of picking up lots of things to get current on the language, Maven, and Spring itself.  I realized that it was VERY difficult to even START a spring application and there was lots of confusing documentation out there that used both XML and Java Configurations and it was hard to find the right information at the right time.

That’s where Spring Boot stepped in.

Spring Boot

Spring Boot has felt like a breathe of fresh air to me.  It’s focused Spring itself on an ‘opinionated’ stack (i.e. choices made for you for common scenarios) while still allowing overrides for those opinions in order to solve specific issues or decisions you have made or just plain prefer (i.e. want to use log4j instead of logback?  no problem, just add it to your classpath.  want to use Eclipse Link instead of Hibernate?  spring boot has you covered).

My first test of spring boot was to try to to write a simple application that used multiple databases.  The scenario was multiple Profiles, minimally 1 for dev and 1 for production.  I wanted to see how Spring Boot would allow me to seamlessly switch between profiles and how quick and effortlessly (or not) this would be, so I created a simple application at https://github.com/jimbasilio/SpringBoot-profiles.

While profiles may not be the sexiest topic, it’s one that is pretty important when developing an application in order to be able to quickly transition from your dev environment to your production environment (with ideally a test environment to boot). In the spring docs it has a section devoted to profiles.

The Spring Boot Documents (1.1.0) are a GREAT source of information and pointers to example projects from the Spring team itself, but sometimes they don’t go deep enough. For my test project I added both h2 and hsqldb to my classpath via my pom.xml file.

hsqldb and h2

This pulls both databases in for access via spring, which you can then specify settings in your application*.properties files to decide what you want to use, and more importantly when. In order to specify the ‘when’ for using different databases you simply need to pass an argument to spring boot via the JVM parameters:

After some experience at work, I realized that choosing profile definitions based on environment (i.e. dev or prod) is not a good idea. It’s too inflexible. Instead, creating profiles for each segment of your app that you want to pull in is preferred.

For example, if you have multiple databases to support, define a profile for each (application-hsql.profile, application-h2.profile). This way you are able to shuffle in different features to test without having to dictate what a ‘production’ environment is. Instead, define your production environment based on the profiles you need to use and put these on the commandline that you will run in production.

Another example is if you want an awesome feature on at TIMES, but by default this feature can be off. When you include the properties definition you can default it to false:

awesome feature disabled

But when you are ready to turn this feature on you can simply put it on your commandline and it’ll pull in the properties file and turn it on:

with awesome feature

When you add the ‘awesomefeature’ to the commandline and visit the controller you’ll see the proper text indicating the feature is active.

awesome feature browser

Summary

So in summary, spring boot is great for getting off the ground QUICKLY with all the goodness that spring provides. It allows you to hook in and dictate the behavior you want (not discussed in this blog) and also has the ability to select ‘profiles’ that can be used for all sorts of useful combinations of features when testing and building to production.

Hope you enjoyed reading!