Spring-boot + Couchbase + Docker = Nirvana

I actually meant it when I wrote the title :). Spring boot gives you the power of super fast development with a load of tools and configuration options, Couchbase is one of the most matured and feature-rich No-Sql databases that exist on planet earth and Docker is perhaps the most amazing piece of container technology that has blessed the human race in recent years. Put together, these make an awesome threesome.

All catchy stuff so far, let’s get real. I have a simple couchbase-backed spring-boot app which lets an user create/view/update/delete his daily expenses. The front-end is powered by vaadin which is another cool technology (especially if you don’t like javascript that much). To start with, go to start.spring.io and select spring-boot,couchbase and vaadin as your dependencies. I am using one of the vaadin add-ons named viritin; you need to add that too in your pom or ivy build file. To integrate with couchbase, you need a repository and an entity. With spring-boot this is super easy. Just create a java interface called ExpenseDetailsRepository which needs to extend the spring data CouchbasePagingAndSortingRepository. I have added custom methods because I am returning a list of entities here.

/**
 * @author eratnch
 *
 */
@ViewIndexed(designDoc = “expenseDetail”)
@N1qlPrimaryIndexed
public interface ExpenseDetailsRepository extends CouchbasePagingAndSortingRepository<ExpenseDetail, String> {
 
 List<ExpenseDetail> findAll();
 
 List<ExpenseDetail> findByTransactionDateBetween(Date fromDate, Date toDate);
 
 List<ExpenseDetail> findByMerchant(String merchantName);
 
 List<ExpenseDetail> findByMerchantStartsWithIgnoreCase(String merchantName); 
}

The annotations in the repository ensures that a backing couchbase view named “expenseDetail” will be supplied at runtime. This is great advantage if someone doesn’t want to write the views before-hand. In addition, the framework would ensure that a N1QLPrimaryIndex does exist on the associated bucket of the underlying repository. The Entity class is annotated with @Document which means that the entity will be stored and served as a couchbase document in the bucket. Next thing you need to have a Spring-boot apprunner class and a vaadin UI. For the code, you can follow here.


Why docker…just why

Because it’s a buzzword nowadays. I am kidding :) and yes you have guessed it anyway. Docker is a container technology that has opened up a new direction in the way people build and test softwares. For the context of this post, I assume you already know the usage and docker. If not, you can go through the official docker reference guide to learn what it can do. In the context of the ongoing use case, I needed to do the following

  1. I needed to configure a couchbase server image with full text search, querying and indexing services enabled.
  2. I needed a “default” bucket to be created within the couchbase node.
  3. Once the couchbase image is ready and the bucket configuration is done, my expense tracker app should start in the self-contained tomcat container and connect to the couchbase cluster (single node for the time being).
  4. And that’s it.

Enter Docker-Compose

Docker-compose, as you might be knowing, is a great tool for orchestrating and linking multiple docker containers with single command. By using compose yml files, you save a lot of manual stuff. In my case, I have two containers; one is the app itself and the other is the couchbase 4.5 container with some configuration and set-up stuff included in it. My docker-compose file goes something like this

version: “2”
services:
 expensetracker-cb:
 image: chakrar27/expensetracker-cb
 ports:
 — 8080:8080
 depends_on:
 — mycouchbase
 
 mycouchbase:
 image: chakrar27/couchbase_new_10_08_2016
 ports:
 — 8091:8091
 — 8092:8092 
 — 8093:8093 
 — 8094:8094
 — 11210:11210

Be extra-careful about indentation when writing compose .yml files. Docker-compose is super sensitive about indentation of the text. I have the app container named “chakrar27/expensetracker-cb” which depends on another container named “chakrar27/couchbase_new_10_08_2016”. The keyword “depends_on” ensures that the couchbase_new_10_08_2016 container starts up first and then the app container. It’s a no-brainer; otherwise the app would never connect to the couchbase database. As simple as it may sound, it’s a bit tricky to make sure that the couchbase container is absolutely up and alive and the default bucket is also configured properly. The easy way out is to invoke a shell script and make the app container wait till the db container is properly up with all set-up. In this example, I use the easy approach and just sleep for a long enough time in a script before my app container starts. I will come to this part later.

For configuring the couchbase image with all preset setting and data, you can pull this image from the docker hub. I took lot of help from Arun Gupta’s couchbase and docker related blogs.

If you are not familiar with how to dockerize a spring-boot application, feel free to check this valuable guide from spring io. The key thing to note here is the use of docker-maven-plugin provided by spotify.

Let’s come to the waiting part in the script. Here’s how my dockerfile looks

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD expensetracker-cb-0.1.0.jar app.jar
RUN sh -c ‘touch /app.jar’
ADD test_hello.sh .
RUN chmod +x test_hello.sh
CMD sh test_hello.sh

And here’s how the test_hello.sh goes

#!/bin/bash
#echo $SLEEP_TIME
echo “Starting script ………..”
echo “Put your waiting code here, I will wait for 1 min”
sleep 60
echo “slept well for a minute”
java -Djava.security.egd=file:/dev/./urandom -jar /app.jar

So what happens exactly when you type “docker-compose up” ?

  1. The “mycouchbase” image which is nothing but the chakrar27/couchbase_new_10_08_2016 container is pulled and run. It does all it is supposed to do. That is to create all query, indexing, fts service and create default bucket with initial memory.
  2. Next up, is the app container image. It inspects the dockerfile, adds the .jar file as app.jar in the container and then runs the shell script.
  3. The test_hello.sh takes over and sleeps for a minute with stupid echo statements.
  4. After 60 seconds sleeptime, the script runs the app.jar with arguements which in turn triggers the spring-boot app.

What happens between step 3 and 4 is of great significance. During the 60 second long sleeptime, the couchbase container has enough time to configure the node with all presettings. It actually takes lot less than 60 seconds, but I have kept a larger delay just in case.

So all you have to do to get this running on any pc or environment is to type te following:

docker-compose up -d or docker-compose up and the magic happens.

P.S -> Although the script solution to wait for a sleep_time is not the best solution, it works fine for me with the set-up I described. I need to figure out a way to ping couchbase and the bucket to see if it’s ready to accept client connections. There are some tools provided by couchbase which I need to take a look at. I would blog about it once I find a more elegant solution. However, as I said, this works for me and for now it’s good enough.

Thanks for reading!