A Little Background..
I have a little side project that I develop when I have moments of spare time. It’s a configurable engine that aggregates news feeds, bundles them up and displays them through a variety of web sites and mobile apps.
It’s really just a pet project that I enjoy playing around – especially for learning new tech. It’s been through a few iterations over the last 5 or so years:
- JEE6, Postgres, Squid Server, Glassfish running on a single Slicehosts VM
- Spring, MySQL, Tomcat running on OpenStack
- Spring, Tomcat running on Amazon EC2, MySQL running on Amazon RDS
- Spring, Tomcat running on Amazon Elastic Beanstalk, Postgres running on Amazon RDS (my current setup)
The driving force between each iteration has largely been to make it simpler and more robust As I’ve come to realise with spare time projects – less is more. They are the kind of things I dip into when I have a few days/weeks spare, and then don’t touch for prolonged periods of time while real life gets in the way. As such, all time is precious and the more time it takes to get environments configured, and get your head back into the code – the less time you have to actually to the interesting stuff.
In addition, while I’m not working on it – I don’t want to be bothered by it. I need it to run efficiently and quietly without needed any interventions by myself.
In years gone by – I’d occasionally get notifications of servers going down (usually memory/disk space) issues – and have to jump in, roll up the sleeves and get it all working again. Since moving to Elastic Beanstalk (and generally upgrading the app code) over the last couple of years – it’s been completely hands off for me. The server keeps discovering and making available new news items, cleaning up and pruning old ones and Amazons infrastructure takes care of the rest. Happy days.
The Next Evolution – Spring Boot + Docker
So, it’s working well, but, well – technology moves on and you’ve got to keep up with it. Also – I need to start adding new functionality – and it’s always more enjoyable to discover and play with the latest developments.
So – what’s next in the evolution of my app (aside from a Java 8 upgrade)?
My main drivers are being able to pick up and work with the codebase easier. From cold, get everything up and running on my local dev environment asap and with minimal fuss (I like to rebuild my iMac every now and again – so like to have an easily recreated, lightweight and transparent dev environment)
On the back of this then – there are 2 changes I want to make (which I’m already sold on both from previous work).
The first is Spring Boot – my Spring setup is pretty lean as it is – I use Spring extensively (Spring Data, Spring MVC, Scheduling, etc) – and I’ve mostly moved to Java config, but there are a few XML config stragglers. Up until now, I’ve been building the usual WAR and deploying it to Tomcat/Jetty. Converting to Spring Boot is an opportunity to streamline this even more – get rid of XML config completely, and make the existing code even more lean with the auto config options.
The second is the use of Docker. After a machine rebuild a while ago I had to go through the motions of getting Postgres installed again – and it just all felt a bit klunky and brittle. I had a look at other options – and had a play with running a Docker Postgres image through Kinematic. It was a breeze – nice, simple and self contained – check out my full post here – https://www.adrianmilne.com/installing-postgres-with-dockerkinematic-on-os-x-in-under-30-mins/.
Why Spring Boot?
- Embedded server – self contained in the application
- Minimal configuration
- Simple pom dependencies
- No XML required
- Production ready
- Lightweight
- Easily containerised
- Easy to script/deploy
Why JAX-RS?
- Most REST Spring Boot examples use Spring MVC for web service endpoints. My existing project had traditionally used JAX-RS (since the JEE days)
- I had some dependencies on Jersey specific libraries – for generating JSONP (JSON with padding) – for some historical reason with my web site access. I need to revisit the reasons for this after my planned web site updates – but for now, I’d prefer to keep as-is – so JAX-RS is prerequisite.
Why Docker?
- Experience so far has been positive
- Seems to be becoming an industry standard (check out my review of last years JAXLondon Java Conference – where Docker was one of the hot topics – https://www.adrianmilne.com/my-top-tech-takeaways-jax-london-2015/)
- Also – I’m still figuring this one out – so this is all part of the learning experience for me for now
Running My Sample Application
- I hit a few issues while converting my existing application – I got over most of them, but had a couple of lingering ones.
- I decided to step back, and just create a very simple demo application instance to check the basics all worked for me (i.e. Spring Boot, JAX-RS, Docker, Docker Toolbox) – I find this is generally a good approach if you’re refactoring a reasonably complex existing application – just to check you have the basics covered first
- So this application is going to be a simple “Hello World” Spring Boot app – using JAX-RS/Jersey, containerised with Docker, running on OSX.
Source Available on GitHub
Pre-requisites
- Java 1.8
- Maven
- Java IDE (I used IntelliJ for this – I usually use Eclipse – but trying to get more familiar with IntelliJ now)
- Docker Toolbox
Running the Application Outside Docker
- Check out the app from GitHub
- Open in your IDE (in my example it is IntelliJ – but similar in Eclipse)
- Run com.cor.Application – this will run the Spring Boot application like in the screen shot below
- Open your browser and go to:
http://localhost:8080/mytestapp/demo/hello
- The following screen will appear
- Cool – so now we have a working Spring Boot app that is exposing a REST service using JAX-RS/Jersey
Building for Docker
- We now need to convert our Spring Boot app to a Docker container and deploy it to our local Docker server
- Firstly – start Docker Terminal
- Next, we need to add some environment variables to tell maven where Docker is installed
DOCKER_CERT_PATH=/Users/adrianmilne/.docker/machine/machines/default DOCKER_HOST=https://192.168.99.100:2376
- You can add these any way you want, the way I did it was to create a new Maven Run Configuration which would:
- Set up the necessary environment variables above
- run ‘mvn package docker:build’
- Execute the run configuration above to run ‘mvn package docker:build’
- In the Docker terminal window – try typing
docker images
- This will show that your Spring boot app has been built and deployed to your local Docker
Running the Application Inside Docker
- You can run the application in the Docker container by typing:
docker run -P -d --name spring-boot-docker corsoft/spring-boot-docker
- This will start the container.
- If you open Kinematic at this point you can see the container starting up
- If you click on Settings .. Ports in Kinematic – you can see what IP/Port it has been made available on
-
- in this case:
http://192.168.99.100:32770
-
- If you point your browser at that address – you can now access your Spring Boot app running inside Docker
The Application Components
Creating a Spring Boot Application
- This is already pretty well documented here (and elsewhere): http://projects.spring.io/spring-boot/
Adding JAX-RS Support
- Adding JAX-S is as simple as adding a new dependency in the maven file
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency>
- And then adding a new ResourceConfig to register the Service endpoints you are going to use:
package com.cor; import com.cor.service.HelloWorldService; import org.glassfish.jersey.server.ResourceConfig; import org.springframework.stereotype.Component; /** * Created by adrianmilne on 04/08/2016. */ @Component public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(HelloWorldService.class); } }
Adding a Docker File & docker-maven-plugin
Add a new file called ‘Dockerfile’ (note the case – I got caught out by putting a capital ‘F’ in for a while – which just resulted in vague HTTP 500 errors from the docker server when trying to build it)
This goes under src/main/docker (configurable via the plugin below)
FROM java:8 VOLUME /tmp EXPOSE 8080 ADD spring-boot-docker-demo.jar app.jar RUN sh -c 'touch /app.jar' ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]</pre>
You then just need to add the docker-maven-plugin as below (note the reminders to set the docker environment variables – covered above)
Everything in the Dockerfile can be configured in the docker-maven-plugin if needed, but I preferred to use a Dockerfile to get more familiar with the native settings and syntax.
<build> <finalName>spring-boot-docker-demo</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>0.4.5</version> <configuration> <!-- NOTE: These Environment Variables Need to be set for Docker Toolbox on your machine DOCKER_CERT_PATH=/Users/adrianmilne/.docker/machine/machines/default DOCKER_HOST=https://192.168.99.100:2376 --> <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> </plugins> </build>
Conclusion
And that’s basically that – very simple to set up once you know what needs to be done (had a few issues to overcome along the way – which was why I thought it was worth sharing).
Next step would be to replace my Amazon Tomcat Elastic Beanstalk deployment with a Docker one. I started looking into this – looks like I need to deploy my container to Docker Hub (or similar) – and then I can reference it from there the Elastic Beanstalk setup.
(and then apply all this to my existing application)
Think that could form the basis for a follow up article!
Full source available on github @ https://github.com/adrianmilne/spring-boot-docker-jaxrs-demo