Using Azure Kubernetes Services for Java Spring Boot Microservices
Tim Kelly9 min read • Published Apr 15, 2024 • Updated Apr 15, 2024
FULL APPLICATION
Rate this tutorial
In the early days of software development, application development consisted of monolithic codebases. With challenges in scaling, singular points of failure, and inefficiencies in updating, a solution was proposed. A modular approach. A symphony of applications managing their respective domains in harmony. This is achieved using microservices.
Microservices are an architectural approach that promotes the division of applications into smaller, loosely coupled services. This allows application code to be delivered in manageable pieces, independent of each other. These services operate independently, addressing a lot of the concerns of monolithic applications mentioned above.
While each application has its own needs, microservices have proven themselves as a viable solution time and time again, as you can see in the success of the likes of Netflix.
In this tutorial, we are going to deploy a simple Java Spring Boot microservice application, hosted on the Azure Kubernetes Service (AKS). AKS simplifies deploying a managed Kubernetes cluster in Azure by offloading the operational overhead to Azure. We'll explore containerizing our application and setting up communication between our APIs, a MongoDB database, and the external world. You can access the full code here:
Though we won't dive into the most advanced microservice best practices and design patterns, this application gives a simplistic approach that will allow you to write reviews for the movies in the MongoDB sample data, by first communicating with the review API and that service, verifying that the user and the movie both exist. The architecture will look like this.
Simple, right? Exactly! And AKS makes it even easier to communicate with other APIs managed on the service. In a microservices architecture, services need to discover each other dynamically. Kubernetes itself acts as a service registry, where each service in the cluster has a unique name. So when we communicate with our other services in ReviewController.java, we simply send a request to
http://user-management-service/users/
. In this demo application, communication is done with RESTful HTTP/S requests, using RestTemplate.Before you begin, you'll need a few prerequisites to follow along with this tutorial, including:
- A MongoDB Atlas account, if you don't have one already, with a cluster ready with the MongoDB sample data.
- Azure CLI, or you can install Azure PowerShell, but this tutorial uses Azure CLI. Sign in and configure your command line tool following the steps in the documentation for Azure CLI and Azure PowerShell.
- Docker for creating container images of our microservices.
- Java 17.
- Maven 3.9.6.
Starting from the very beginning, set up an Azure Kubernetes Service (AKS) cluster.
Install
kubectl
, the Kubernetes command-line tool, via the Azure CLI with the following command (you might need to sudo this command), or you can download the binaries from:Log into your Azure account using the Azure CLI:
Create an Azure Resource Group:
Create an AKS cluster: Replace
myAKSCluster
with your desired cluster name. (This can take a couple of minutes.)After successfully creating your AKS cluster, you can proceed to configure
kubectl
to use your new AKS cluster. Retrieve the credentials for your AKS cluster and configure kubectl
:Create an ACR to store and manage container images across all types of Azure deployments:
Note: Save the app service id here. We’ll need it later when we are creating a service principal.
Log into ACR:
Each of your applications (User Management, Movie Catalogue, Reviews) has a
Dockerfile
. Create a .jar by running the command mvn package
for each application, in the location of the pom.xml file. Depending on your platform, the following steps are slightly different.For those wielding an M1 Mac, a bit of tweaking is in order due to our image's architecture. As it stands, Azure Container Apps can only jive with linux/amd64 container images. However, the M1 Mac creates images as
arm
by default. To navigate this hiccup, we'll be leveraging Buildx, a handy Docker plugin. Buildx allows us to build and push images tailored for a variety of platforms and architectures, ensuring our images align with Azure's requirements.To build your image, make sure you run the following command in the same location as the
Dockerfile
. Repeat for each application.Or you can run the following command from the simple-movie-microservice folder to loop through all three repositories.
If you are using an M1 Mac, use the following commands to use Buildx to create your images:
Next, enable Buildx to use the Docker CLI:
Open a terminal and navigate to the root directory of the microservice where the
Dockerfile
is located. Run the following command to build the Docker image, replacing movie-catalogue-service
with the appropriate name for each service.Now, we're ready to tag and push your images. Replace
<your-acr-name>
with your actual ACR name. Repeat these two commands for each microservice.Or run this script in the terminal, like before:
Now that we have our images ready, we need to create Kubernetes deployment and service YAML files for each microservice. We are going to create one mono-file to create the Kubernetes objects for our deployment and services. We also need one to store our MongoDB details. It is good practice to use secrets for sensitive data like the MongoDB URI.
First, you'll need to create a secret to securely pass the MongoDB connection string to your microservices. In Kubernetes, the data within a secret object is stored as base64-encoded strings. This encoding is used because it allows you to store binary data in a format that can be safely represented and transmitted as plain text. It's not a form of encryption or meant to secure the data, but it ensures compatibility with systems that may not handle raw binary data well.
Create a Kubernetes secret that contains the MongoDB URI and database name. You will encode these values in Base64 format, but Kubernetes will handle them as plain text when injecting them into your pods. You can encode them with the bash command, and copy them into the YAML file, next to the appropriate data keys:
Run the following command to apply your secrets:
So, while base64 encoding doesn't secure the data, it formats it in a way that's safe to store in the Kubernetes API and easy to consume from your applications running in pods.
If your ACR is private, you'll need to ensure that your Kubernetes cluster has the necessary credentials to access it. You can achieve this by creating a Kubernetes secret with your registry credentials and then using that secret in your deployments.
The next step is to create a service principal or use an existing one that has access to your ACR. This service principal needs the
AcrPull
role assigned to be able to pull images from the ACR. Replace <your-service-principal-name>
, <your-subscription-id>
, <your-resource-group-name>
, and <your-acr-name>
with your own values. : This can be any unique identifier you want to give this service principal. : You can get the id for the subscription you’re using with az account show --query id --output tsv
. : Use the same resource group you have your AKS set up in. : This is the Azure Container Registry you have your images stored in.This command will output JSON that looks something like this:
appId
is your<your-service-principal-app-id>
.password
is your<your-service-principal-password>
.
Note: It's important to note that the
password
is only displayed once at the creation time. Make sure to copy and secure it.Create a Kubernetes secret with the service principal's credentials. You can do this with the following command:
There are a couple of points to note in the YAML file for this tutorial, but these points are not exhaustive of everything happening in this file. If you want to learn more about configuring your YAML for Kubernetes, check out the documentation for configuring Kubernetes objects.
- We will have our APIs exposed externally. This means you will be able to access the endpoints from the addresses we'll receive when we have everything running. Setting the
type: LoadBalancer
triggers the cloud provider's load balancer to be provisioned automatically. The external load balancer will be configured to route traffic to the Kubernetes service, which in turn routes traffic to the appropriate pods based on the service's selector. - The
containers:
section defines a single container namedmovie-catalogue-service
, using an image specified by<your-container-registry>/movie-catalogue-service:latest
. containerPort: 8080
exposes port 8080 inside the container for network communication.- Environment variables
MONGODB_URI
andMONGODB_DATABASE
are set using values from secrets (mongodb-secret
), enhancing security by not hardcoding sensitive information. imagePullSecrets: - name: acr-auth
allows Kubernetes to authenticate to a private container registry to pull the specified image, using the secret we just created.
Remember, before applying your Kubernetes YAML files, make sure your Kubernetes cluster has access to your ACR. You can configure this by granting AKS the ACRPull role on your ACR:
Replace
<your-AKS-Cluster>
, <your-resource-group>
, and <your-ACR>
with your AKS cluster name, Azure resource group name, and ACR name, respectively.Apply the YAML file with
kubectl
:Once deployed, it may take a few minutes for the LoadBalancer to be provisioned and for the external IP addresses to be assigned. You can check the status of your services with:
Look for the external IP addresses for your services and use them to access your microservices.
After deploying, ensure your services are running:
Access your services based on the type of Kubernetes service you've defined (e.g., LoadBalancer in our case) and perform your tests.
You can test if the endpoint is running with the CURL command:
And this review should now appear in your database. You can check with a simple:
Hooray!
As we wrap up this tutorial, it's clear that embracing microservices architecture, especially when paired with the power of Kubernetes and Azure Kubernetes Service (AKS), can significantly enhance the scalability, maintainability, and deployment flexibility of applications. Through the practical deployment of a simple microservice application using Java Spring Boot on AKS, we've demonstrated the steps and considerations involved in bringing a microservice architecture to life in the cloud.
Key takeaways:
- Modular approach: The transition from monolithic to microservices architecture facilitates a modular approach to application development, enabling independent development, deployment, and scaling of services.
- Simplified Kubernetes deployment: AKS abstracts away much of the complexity involved in managing a Kubernetes cluster, offering a streamlined path to deploying microservices at scale.
- Inter-service communication: Utilizing Kubernetes' internal DNS for service discovery simplifies the communication between services within a cluster, making microservice interactions more efficient and reliable.
- Security and configuration best practices: The tutorial underscored the importance of using Kubernetes secrets for sensitive configurations and the Azure Container Registry for securely managing and deploying container images.
- Exposing services externally: By setting services to
type: LoadBalancer
, we've seen how to expose microservices externally, allowing for easy access and integration with other applications and services.
The simplicity and robustness of Kubernetes, combined with the scalability of AKS and the modularity of microservices, equip developers with the tools necessary to build complex applications that are both resilient and adaptable. If you found this tutorial useful, find out more about what you can do with MongoDB and Azure on our Developer Center.
Are you ready to start building with Atlas on Azure? Get started for free today with MongoDB Atlas on Azure Marketplace.
Top Comments in Forums
There are no comments on this article yet.