Cloud native application made easy: part one, Spring boot

Updated: Apr 13

This is a series of articles for learning how to develop cloud-native applications with different tools and technics. The series will cover a lot of modern frameworks and production-ready tools for building and deploying microservices such as Spring Boot, Docker, Istio, Kubernetes/OpenShift, QuarKus, etc.



I always believe the best way to learn something new is to jump right in and start doing a simple example to play around it. Once you have experimented with the simple application, you get the necessary knowledge and the most common things that needed to use the particular technology. The objective of this series is to mitigate the theory as much as possible, because, a lot of articles and books already written about Microservices, Docker, OpenShift, etc. If you are an impatient developer like me, the series is for you. The series of posts is intended for programmers who want to get started using Spring Boot, Docker, OpenShift, Istio as quickly as possible, but also want to understand a little bit of what they are doing.


So, in this part of this article, I am going from scratch: developing a very simple microservice application with Spring boot; deploy the service into Docker. In the next part of this series, we will complicate our application and discover how to deploy the service into OpenShift or MiniShift; using service mesh like Istio for adding additional capabilities like routing, resilience, load balancing and so on. Stay tuned.

The complete source code of the article is available in the GitHub repository.

As a developer, you might already have some of these tools described below, but for

completeness, here are the tools that we are going to use:


Step 1. Build a Basic microservice

Get started quickly with Spring Boot by creating a new project that uses the Spring Initializr. Use the following project metadata to generate a Maven project with all the necessary dependencies.

Group: com.blu.std
Artifact: springboot-hello-world

Note that, you will use these above values throughout the rest of this example.


Download generated the project and unarchive it somewhere in your file system. Alternatively, you can download the complete project from the GitHub repository and start modifying it.


Step 2. Maven docker plugin

Add the following Maven plugin to build and deploy a Docker image from the project.

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.33.0</version>
    <configuration>
        <images>
            <image>
                <name>spring-boot-helloworld-docker</name>
                <build>
                    <contextDir>${project.basedir}</contextDir>
                </build>
                <run>
                    <ports>
                        <port>8080:8080</port>
                    </ports>
                </run>
            </image>
        </images>
    </configuration>
</plugin>

I'm using the plugin version 0.33.0 and the port 8080 which will be exposed to invoke the REST API outside the container.


Step 3. Add a web controller

In the Spring MVC framework, an HTTP request is handled by a controller. You can add a controller by using the @Controller annotation. Create a new Java class named "DemoController" in the com.blu.std package as follows:

@RestController
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @RequestMapping("/")
    public String index() {
        return "Spring Boot Hello-world application for demo!";
    }

    @RequestMapping("/getQuote")
    public String getQuote() {
        final String[] todaysQuote = new String[]{
                "Today you are you!",
                "Today was good.",
                "Today is the only day.",
                "What is not started today is never finished tomorrow."
        };
        final int rnd = new Random().nextInt(todaysQuote.length);

        return todaysQuote[rnd];
    }
}

Here, @RestController is a special type of web @Controller. Spring consider this annotation when handling incoming web request.

The @RequestMapping annotation provides routing information for the web application. It informs Spring that any HTTP request with / path should be routed to the home() method. Accordingly, HTTP request with /getQuote path would be routed to the getQuote() method. The above getQuote() method returns a random today's quote from the array of a string.


Step 4. Build and test the Spring Boot application.

To build the project, run the following command from your favorite terminal.

mvn clean install

At this point, the project is ready to run. Execute the following command from the project home directory.

mvn spring-boot:run

You should see output similar to the following:

21:28:26.030 [main] INFO com.blu.std.App - Spring Boot Hello-World app runs!

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)

2020-04-12 21:28:26.627  INFO 2673 --- [           main] com.blu.std.App                          : Starting App on shamim.local with PID 2673 (/Users/shamim/Development/workshop/github/Microservices-nutsAndbolts/CloudNative-application/springboot-hello-world/target/classes started by shamim in /Users/shamim/Development/workshop/github/Microservices-nutsAndbolts/CloudNative-application/springboot-hello-world)
2020-04-12 21:28:26.628  INFO 2673 --- [           main] com.blu.std.App                          : No active profile set, falling back to default profiles: default
2020-04-12 21:28:27.489  INFO 2673 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2020-04-12 21:28:27.501  INFO 2673 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2020-04-12 21:28:27.501  INFO 2673 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
2020-04-12 21:28:27.571  INFO 2673 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2020-04-12 21:28:27.571  INFO 2673 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 903 ms
2020-04-12 21:28:27.811  INFO 2673 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-12 21:28:27.946  INFO 2673 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-04-12 21:28:28.004  INFO 2673 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-04-12 21:28:28.008  INFO 2673 --- [           main] com.blu.std.App                          : Started App in 1.883 seconds (JVM running for 2.247)

Open another terminal and run the following URL. Alternatively, you can open a web browser to http://localhost:8080/getQuote.

curl http://localhost:8080/getQuote ;echo

You should see the following output:

What is not started today is never finished tomorrow.

Step 5. Run the Spring Boot application in the native Java way.

You can use Java -jar command to run the application as follows:

java -jar ./target/springboot-hello-world-1.0-SNAPSHOT.jar

To exit the application, press crtl-c.


Step 6. Building docker images

Create a new file with the name Dockerfile and place the file into the home directory of the project. Add the following content into it.

FROM openjdk:8-jre-alpine
RUN mkdir /app
COPY ${project.artifactId}.jar /app
CMD ["java", "-jar", "/app/${project.artifactId}.jar"]

I start my image from a base image called openjdk:8-jre-alpine. You can start your images from any valid images that you pull from the public docker registry. Then I create a directory called app. The next instruction copy the resulted jar file into the /app directory. The final line of the Dockerfile executes the jar file with Java -jar command.

To build the docker image, run the following command:

mvn docker:build

The above command will build and push the image spring-boot-helloworld-docker into the docker local repository. You can check the newly created image in the Docker. Execute the following docker command to list all the top-level images as follows:

docker images

You should see the following output.

$ docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
spring-boot-helloworld-docker          latest              9ac5a67d5334        2 minutes ago       104MB
yandex/clickhouse-server1              latest              53c7fa8c94e2        2 weeks ago         493MB
yandex/clickhouse-server               latest              f62e485ae47b        3 weeks ago         492MB
yandex/clickhouse-client               latest              bf3b797512b0        3 weeks ago         484MB
openjdk                                8-jre-alpine        f7a292bbb70c        11 months ago       84.9MB
spoonest/clickhouse-tabix-web-client   latest              e872c1a905d9        23 months ago       245MB

Now that we have our image built, it's time to create a docker container and run the application. Open a new terminal and execute the following command:

docker run -d -p 8080:8080 spring-boot-helloworld-docker

Here, we create a new container from the image and exposed the port 8080 to the outside of the container. Check the container status as follows:

docker ps -a

The output of the above command should be something similar as shown below:

$ docker ps -a
CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS                     PORTS                    NAMES
19738d945307        spring-boot-helloworld-docker          "java -jar /app/spri…"   5 seconds ago       Up 4 seconds               0.0.0.0:8080->8080/tcp   friendly_chaum
43c7d05de244        spoonest/clickhouse-tabix-web-client   "/bin/sh -c ./start.…"   13 days ago         Exited (137) 13 days ago                            epic_rosalind
d151ce364eee        yandex/clickhouse-server1              "/entrypoint.sh"         2 weeks ago         Exited (137) 13 days ago                            some-clickhouse-server1
9adf5b1925f0        yandex/clickhouse-server               "/entrypoint.sh"         2 weeks ago         Exited (137) 2 weeks ago                            some-clickhouse-server

Congratulations! You have just finished the first part of the article. Browse to the REST endpoint and you should see the following response.

Today you are you!

Summary

In this blog post, we learned how to build and deploy a basic Spring boot application. First, we developed an application and run on a standalone mode. Later, we built a Docker image through a Maven plugin and deploy it into the docker and run a container based on the image.


Homework.

1. Add a new method into the DemoController Java class which will return an n-th Fibonacci Number from a given number.

2. Build a Docker image with the native Docker command.


Please Note

email us at:

  • Twitter
  • LinkedIn
Join our mailing list

© 2020 Shamim bhuiyan