loading...
Cover image for Docker and Java Spring Boot [Part.1: Continuous Integration]
Semaphore

Docker and Java Spring Boot [Part.1: Continuous Integration]

tomfern profile image Tomas Fernandez Originally published at jaxenter.com Updated on ・5 min read

This post was originally published in jaxenter.

In this tutorial, we will learn how Continuous Integration and Delivery can help us to test and prepare a Java application for Docker.

A Continuous Integration (CI) setup will test our code on every update. The practice creates a strong feedback loop that reveals errors as soon as they are introduced. Consequently, we can spend more of our time coding features rather than hunting bugs.

We will use Docker for packaging since it’s supported universally across all cloud providers. Furthermore, Docker is a requirement for more advanced deployments such as Kubernetes. In the second part of the tutorial, we’ll learn your we can use Continuous Deployment (also CD) to deploy new versions to Kubernetes at the push of a button.

Getting Ready

Here’s a list of the things you’ll need to get started.

  • Your favorite code IDE and the Java SDK.
  • A Docker Hub account and Docker.
  • A GitHub account and Git.

Let’s get everything ready. First, fork the repository with the demo and clone it to your machine.

The application is built in Java Spring Boot and it exposes some API endpoints. The project includes tests, benchmarks and everything needed to create the Docker image.

Continuous Integration

We’ll use Semaphore as our Continuous Integration solution. Our CI/CD workflow will:

  1. Download Java dependencies.
  2. Build the application JAR.
  3. Run the tests and Jmeter benchmarks. And, if all goes well…
  4. Create a Docker image and push it to Docker Hub.

But first, open your browser at Semaphore and sign up with GitHub; that will link up both services. The free account includes 1300 monthly build minutes. Click on the + (plus sign) next to Projects to add your repository to Semaphore:

Add your project to Semaphore

The repository has a sample CI/CD workflow. Choose “I will use the existing configuration”.

Use existing config

Semaphore will show the CI/CD pipelines as soon as you make a push to GitHub. You can create an empty file and push it with Git:

$ touch some_file
$ git add some_file
$ git commit -m "add Semaphore"
$ git push origin master
Enter fullscreen mode Exit fullscreen mode

Or do it directly from the GitHub using the Create New File button.

First Run

Click on the Edit Workflow button to view the recently-released Workflow Builder UI.

Workflow Builder

Each pipeline has a name and an agent. The agent is the virtual machine type that powers the jobs. Semaphore offers several machine types, we’ll use the free e1-standard-2 model with an Ubuntu 18.04.

Jobs define the commands that give life to the CI/CD process, they are grouped in blocks. Click on the “Build” block to view its job:

Build Block

Jobs in a block run concurrently. Once all jobs in a block are complete, the next block begins.

The first job downloads the dependencies and builds the application JAR without running any tests:

checkout
cache restore
mvn -q package jmeter:configure -Dmaven.test.skip=true
cache store
Enter fullscreen mode Exit fullscreen mode

The block uses some of the Semaphore's toolbox scripts: checkout to clone the repository and cache to store and retrieve the Java dependencies.

The second block has two test jobs. The commands that we define in the prologue run before each job in the block:

checkout
cache restore
mvn -q test-compile -Dmaven.test.skip=true
Enter fullscreen mode Exit fullscreen mode

Test Block

The third block starts the application and runs the benchmarks:

java -version
java -jar target/spring-pipeline-demo.jar > /dev/null &
sleep 20
mvn -q jmeter:jmeter
mvn jmeter:results
Enter fullscreen mode Exit fullscreen mode

Store Your Docker Hub Credentials

To securely store passwords, Semaphore provides the secrets feature. Create a secret with your Docker Hub username and password. Semaphore will need them to push images into your repository:

  • Under Configuration click on Secrets.
  • Press the Create New Secret button.
  • Create a secret called “dockerhub” with your username and password:

Create Secret

Continuous Delivery

Next to the benchmark block we find the a promotion which connects the CI and the “Dockerize” pipelines together. Promotions connect pipelines to create branching workflows. Check the Enable automatic promotion option to start the build automatically.

Automatic Promotion

The demo includes a Dockerfile to package the application into a Docker image:

FROM openjdk:8-jdk-alpine
ARG ENVIRONMENT
ENV ENVIRONMENT ${ENVIRONMENT}
COPY target/*.jar app.jar
ENTRYPOINT ["java","-Dspring.profiles.active=${ENVIRONMENT}", "-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
Enter fullscreen mode Exit fullscreen mode

The “Dockerize” pipeline is made of one block with a single job which:

  • Logins to Docker Hub
  • Pulls the latest image
  • Builds the new image with the updated code
  • Pushes the new image
mvn -q package -Dmaven.test.skip=true
echo "$DOCKER_PASSWORD" | docker login  --username "$DOCKER_USERNAME" --password-stdin
docker pull "$DOCKER_USERNAME"/semaphore-demo-java-spring:latest || true
docker build --cache-from "$DOCKER_USERNAME"/semaphore-demo-java-spring:latest \
      --build-arg ENVIRONMENT="${ENVIRONMENT}" \
      -t "$DOCKER_USERNAME"/semaphore-demo-java-spring:latest .
docker push "$DOCKER_USERNAME"/semaphore-demo-java-spring:latest
Enter fullscreen mode Exit fullscreen mode

Testing the Image

Click on the Run the workflow button and then choose Start.

Start Workflow

After a couple of minutes the workflow should be complete and you should have a new Docker image with your application in Docker Hub:

CI/CD Workflow done

By now, you should have a ready Docker image in your repository. Let’s give it a go. Pull the newly created image to your machine:

$ docker pull YOUR_DOCKER_USER/semaphore-demo-java-spring:latest
Enter fullscreen mode Exit fullscreen mode

And start it in your machine:

$ docker run -it -p 8080:8080 YOUR_DOCKER_USER/semaphore-demo-java-spring
Enter fullscreen mode Exit fullscreen mode

You can create a user with a POST request:

$ curl -w "\\n" -X POST \
    -d '{ "email": "wally@example.com", "password": "sekret" }' \
    -H "Content-type: application/json" localhost:8080/users

{"username":"wally@example.com"}
Enter fullscreen mode Exit fullscreen mode

With the user created, you can authenticate and see the
secure webpage:

$ curl -w "\n" --user wally@example.com:sekret localhost:8080/admin/home

<!DOCTYPE HTML>
<html>
<div class="container">
<header>
<h1>
Welcome <span>tom@example.com</span>!
</h1>
</header>
</div>
Enter fullscreen mode Exit fullscreen mode

You can also try it with login page at localhost:8080/admin/home

Next Stop: Kubernetes

See you in Part 2 to learn how to deploy the image to any Kubernetes:

Conclusion

You have set up your first CI/CD pipeline. With this system in place you can work in your code, secure in the feeling that it’s being constantly tested.

Stay tuned for part 2 of the tutorial next week, we’ll see how to do Continuous Deployment to a Kubernetes cluster.

Did you find the post useful? Let me know by ❤️-ing or 🦄-ing below! Do you have any questions or suggestions for other tutorials? Let me know in the comments.

Thank you for reading!

Discussion

pic
Editor guide