Example of a Spring Boot Microservice Running on OSX/Docker Toolbox

Datetime:2016-08-23 03:15:11          Topic: Docker  Microservice           Share

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 websites and mobile apps. It's just a pet project that I enjoy playing around with — it's been especially useful for learning new tech. It's been through a few iterations over the last five or so years, including:

  1. JEE6, Postgres, Squid Server, Glassfish running on a single Slicehosts VM.
  2. Spring, MySQL, Tomcat running on OpenStack.
  3. Spring, Tomcat running on Amazon EC2, MySQL running on Amazon RDS.
  4. 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 work best as the kind of things I can dip into when I have a few days/weeks to spare, and then leave untouched for prolonged periods of time (while real life gets in the way). All time is precious, and the more time it takes to get environments configured, and get my head back into the code — the less time I have to actually to the interesting stuff.

While I'm not working on it — I don't want to be overly distracted 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.

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 I like to have an easily recreated, lightweight and transparent dev environment).

On the back of this then, there are two changes I want to make (which I'm already sold on both from previous dabbles).

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 still lying around. 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 making the existing code even more lean with the auto config options available.

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 clunky 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. Feel free to check out my full post here .

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 .
  • 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 I had a couple of lingering ones.
  • I decided to step back and just create a very simple demo application instance to check if 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

Prerequisites

  • Java 1.8.
  • Maven.
  • Java IDE (I used IntelliJ for this — I usually use Eclipse — but I'm 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 it's 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.
  • First, 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

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;

@Component
public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        register(HelloWorldService.class);
    }

}

Adding a Docker File and 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"]

You then just need to add the docker-maven-plugin as below (note the reminders to set the Docker environment variables, which is 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. It's 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).

The next step would be to replace my Amazon Tomcat Elastic Beanstalk deployment with a Docker one. I started looking into this, and it looks like I need to deploy my container to Docker Hub (or similar), then I can reference it from there the Elastic Beanstalk setup.

That will have to wait for a follow up article though..

Full source available on GitHub .





About List