Java Microservice on Google Kubernetes Engine (GKE) Cluster

Search for a command to run...

No comments yet. Be the first to comment.
This is a dummy component which integrates with binary sensor, lock, sensor and switch platforms for demonstrating the development of custom components used in Home Assistant. Development Setup development environment as described in the following ...
In this article, we'll write a JUnit Test configured with Environment Variables using junit-pioneer library. First of all, we need to add the junit-pioneer library and maven-surefire-plugin to the Maven pom.xml. <project> <properties> <p...
Problem The problem occurs when using the Python requests library, the chardet library is not installed. /Users/adacheng/Library/Python/3.9/lib/python/site-packages/requests/__init__.py:86: RequestsDependencyWarning: Unable to find acceptable charact...

Apache Kafka is an open-source distributed event streaming platform for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications. Introduction This article aims to provide basic hands-on instructions ...

Problem When AWS STS module is included in a Spring Boot Application, exception complaining region not set is thrown. Maven pom.xml <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>sts</artifactId> </dependency> Error M...

Installation Follow the instruction in this article to install Trivy. Scan To scan the docker image: Build the image. docker build . -t hello-world Scan the image. trivy scan hello-world

Java microservices remain as hot topic in 2022.
In this article, I would like to show you the steps to create a Java Microservice, and deploy it to Google Kubernetes Engine (GKE).
Follow the instructions in Install Cloud SDK.
Install Cloud Code Plugin for IntelliJ from Preference -> Plugins. Search by "Cloud Code" in the "Marketplace" tab.

In Google Cloud Shell, perform the following steps:
i. Lists credentialed accounts and make sure the desired account is set active.
gcloud auth list
ii. Create a project.
gcloud projects create PROJECT_ID
iii. Set the default project.
gcloud config set project PROJECT_ID
iv. Print the project ID.
echo $GOOGLE_CLOUD_PROJECT
v. Set the default zone:
gcloud config set compute/zone COMPUTE_ZONE
vi. Set the default region:
gcloud config set compute/region COMPUTE_REGION
vii. Show the configuration.
gcloud config list
Enable Billing in Google Cloud Console.
Enable APIs in Google Cloud Shell.
i. Enable Artifact Registry API.
gcloud services enable artifactregistry.googleapis.com
ii. Enable Kubernetes Engine API.
gcloud services enable container.googleapis.com
iii. Enable Firestore.
gcloud services enable firestore.googleapis.com
Google Cloud Artifact Registry is a successor of Container Registry, in where container images and language packages can be placed.
We will use Artifact Registry to store our container images.
Enable Artifact Registry, if it is not yet enabled.
gcloud services enable artifactregistry.googleapis.com
View a list of supported locations.
gcloud artifacts locations list
Create an artifact repository.
gcloud artifacts repositories create REPO_NAME \
--repository-format=docker \
--location=REPO_REGION \
--description=REPO_DESC \
--version-policy=REPO_POLICY
Replace REPO_NAME with the desired name for your artifact repository.
Replace REPO_REGION with your region, such as europe-west2.
Replace REPO_DESC with the description of your artifact repository.
Replace REPO_POLICY with keyword snapshot or release*.*
Here below is a working example:
gcloud artifacts repositories create ms-docker-image \
--repository-format=docker \
--location=europe-west2 \
--description="Snapshot repository for docker images" \
--version-policy=snapshot
The full name of the created repository will be
$(REPO_REGION)-$(REPO_FORMAT).pkg.dev/$(PROJECT_ID)/$(REPO_NAME)
List all artifact repositories created in the project.
gcloud artifacts repositories list
Enable Kubernetes Engine API, if it is not yet enabled.
gcloud services enable container.googleapis.com
Create a GKE Cluster.
gcloud container clusters create CLUSTER_NAME \
--num-nodes=1 \
--region europe-west2 \
--release-channel regular \
--scopes=datastore,storage-rw,compute-ro
It will take several minutes to create the cluster.
After the cluster is created, get authentication credentials to interact with the cluster.
gcloud container clusters get-credentials CLUSTER_NAME
List all clusters.
gcloud container clusters list
We can also check whether the cluster is created or not in Google Cloud Console -> Kubernetes Clusters.

Spring Boot enables quick development of Java microservices with various dependency and plugin support to Google Cloud technologies.
Complete Source Code can be found in my GitHub repositories.
Generate a Spring Boot application.
To create a Spring Boot application, use the Spring Initializr to generate a simple Spring Boot . Add the following dependencies:
Spring Web
Spring Boot Actuator
Lombok
Spring Boot Actuator provides end points for health check of the application.
Lombok is a Java annotation library that reduces boilerplate code by using annotations.
Click the "Generate" button to download the ZIP file.
Unzip the file to the project root directory.

Modify pom.xml to add dependencies for GCP.
<properties>
<spring-cloud-gcp.version>1.2.8.RELEASE</spring-cloud-gcp.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-data-datastore</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-data-datastore</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-dependencies</artifactId>
<version>${spring-cloud-gcp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Create a Java model class.
The Lombok @Data annotation saves the time of writing the getter and setter functions.
The Lombok @AllArgsConstructor annotation saves the time of writing the constructor.
The @Entity annotation specifies that it is a Firestore entity in datastore mode.
import org.springframework.cloud.gcp.data.datastore.core.mapping.Entity;
import org.springframework.data.annotation.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
@Entity
@Data
@AllArgsConstructor
public class CustomerAccount {
@Id
private Long accountId;
private String lastName;
private String firstName;
}
Create a Spring Repository interface for Google Datastore.
import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CustomerAccountRepository extends DatastoreRepository<CustomerAccount, Long> {
List<CustomerAccount> findByLastName(String name);
}
Create a Java Controller class for REST endpoints.
The Lombok @RequiredArgsConstructor annotation saves the time of writing the constructor.
The Lombok @Slf4j annotation facilitates SLF4J for logging with the least configurations.
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@RestController
@Slf4j
@RequiredArgsConstructor
public class CustomerAccountController {
private final CustomerAccountRepository customerAccountRepository;
@GetMapping("/api/customerAccounts")
public Iterable<CustomerAccount> getAllCustomerAccounts() {
log.debug("->getAllCustomerAccounts");
return customerAccountRepository.findAll();
}
@GetMapping("/api/customerAccount/{lastName}")
public List<CustomerAccount> findByLastName(@PathVariable("lastName") String name) {
log.debug("->findByLastName");
return customerAccountRepository.findByLastName(name);
}
@PostMapping("/api/customerAccounts")
public CustomerAccount saveCustomerAccount(@RequestBody CustomerAccount customerAccount) {
log.debug("->saveCustomerAccount {}", customerAccount);
return customerAccountRepository.save(customerAccount);
}
}
Enable Spring Boot Actuator in application.properties.
management.endpoint.health.enabled=true
In IntelliJ Terminal,
Lists credentialed accounts and make sure the desired account is set active.
gcloud auth list
Set the default project.
gcloud config set project PROJECT_ID
Show the configuration.
gcloud config list
Start the Spring Boot application.
./mvnw spring-boot:run
Use a REST client, like Postman, to perform following tests:
Perform health check.

Test application function: Create new Customer Account.

Test application function: Find by Last Name.

Test application function: List all Customer Accounts.

In general, we need to write a Dockerfile to dockerize the microservice.
However, in this exercise, we will use Google Cloud's Jib Maven Plugin to build the container images without writing a Dockerfile.
Add Jib Maven plugin in pom.xml.
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.1.4</version>
<configuration>
<to>
<image>europe-west2-docker.pkg.dev/java-microservice-2022/ms-containers/${project.artifactId}</image>
</to>
</configuration>
</plugin>
At the project root, execute the following command:
./mvnw install jib:build
This will build the docker image and publish it to the Artifact Registry.
Use the following command to list docker images in the Artifact Registry.
gcloud artifacts docker images list FULL_CONTAINER_NAME
Or you can check the image in Google Cloud Console.

In this process, we need to write manifest files in YAML format. One is deployment.yaml and the other is service.yaml.
Write deployment.yaml and put it in the project root directory.
apiVersion: apps/v1
kind: Deployment
metadata:
name: account-service-deployment
spec:
selector:
matchLabels:
app: account-service-pod
replicas: 1
template:
metadata:
labels:
app: account-service-pod
spec:
containers:
- name: account-service-container
image: europe-west2-docker.pkg.dev/java-microservice-2022/ms-containers/ms.client.account.gcp
ports:
- containerPort: 8080
livenessProbe:
initialDelaySeconds: 20
httpGet:
port: 8080
path: /actuator/health
readinessProbe:
initialDelaySeconds: 30
httpGet:
port: 8080
path: /actuator/health
Replace account-service-deployment with the name of your deployment.
Replace account-service-pod with the name of your pod.
Replace account-service-container with the name of your container.
Write server.yaml and put it in the project root directory.
apiVersion: v1
kind: Service
metadata:
name: account-service
spec:
type: NodePort
selector:
app: account-service-pod
ports:
- port: 8080
targetPort: 8080
Replace account-service with the name of your service.
Replace account-service-pod with the name of your pod.
Add a new Run/Debug Configuration for Cloud Code: Kubernetes.

Change the name of the Configuration.

Click the "Initialize" button in the "Build/Deploy" tab.

Click the "pen" icon under Build Settings.

Select Jib Maven Pluin from the Builder dropdown list and click the "OK" button.

Click the "Initialize" button.


A skaffold.yaml file will be generated at the Project Root Directory.

Click the "Run" tab.

An alert message "Current Kubernetes context unknown. Please ensure you have Kubernetes clusters configured on your machine (such as minikube or GKE)." in red in shown.
To fix this problem, get authentication credentials to interact with the cluster by typing the following command in Terminal of InteglliJ.
gcloud container clusters get-credentials CLUSTER_NAME
The problem should then be solved.

Please note that the granted credentials are valid in this session only. If your session to Google Cloud is lost, you have to get the credentials again.
At last, make sure the option "Delete deployments when finished" is unchecked.

Click the "OK" button to finish the configuration.
Click the "Run" button of the Cloud Code: Kubernetes configuration just created.

The deployment process should be started.

Once the deployment is finished, test locally using the health check endpoint provided by Spring Actuator.
http://localhost:8080/actuator/health

In IntelligJ Terminal, type the following command to list the services.
kubectl get service

The following command lists the service details in yaml format.
kubectl get service account-service --output yaml
Expose with a target of 8080 using the following command.
kubectl expose deployment {deployment-name} --name={load-balancer-service-name} --type=LoadBalancer --port 80 --target-port 8080
Here is the actual command I used in this exmaple.
kubectl expose deployment account-service-deployment --name=lb-account-service-gcp --type=LoadBalancer --port 80 --target-port 8080
Use the following command to check the progress:
kubectl get service
It may take several minutes to bind the external IP address.

Keep trying until an external IP address is bound.

With the external IP, we can now perform tests.
Health Check using external IP:

Create new Customer Account using external IP:

List all Customer Accounts using external IP:

Find Customer Account by Last Name using external IP:

Remember to clean up in order to avoid incurring cost.
kubectl delete service account-service
gcloud container clusters delete ms-cluster --region europe-west2-c
Hoorays!
We had created a Java Microservice, which interface with Google Cloud's NoSQL database. We then created a GKE cluster and deployed our microservice to it.