This topic discusses using Docker with Spring Boot for VMware Tanzu GemFire.
The state of modern software application development is moving towards containerization. Containers offer a controlled environment to predictably build (compile, configure and package), run, and manage your applications in a reliable and repeatable manner, regardless of context. In many situations, the intrinsic benefit of using containers is obvious.
Understandably, Docker’s popularity took off like wildfire, given its highly powerful and simplified model for creating, using and managing containers to run packaged applications.
Docker’s ecosystem is also impressive, with the advent of Testcontainers and Spring Boot’s dedicated support to create packaged Spring Boot applications in Docker images that are then later run in a Docker container.
Tip | See also Deploying to Containers to learn more. |
VMware GemFire can also run in a controlled, containerized environment. The goal of this chapter is to get you started running VMware GemFire in a container and interfacing to a containerized VMware GemFire cluster from your Spring Boot, VMware GemFire client applications.
This chapter does not cover how to run your Spring Boot, VMware GemFire client applications in a container, since that is already covered by Spring Boot (see the Spring Boot documentation for Docker images and container deployment, along with Docker’s documentation). Instead, our focus is on how to connect to a VMware GemFire cluster in a container from a Spring Boot, VMware GemFire client application, regardless of whether the application runs in a container or not.
First, set up your containerized VMware GemFire cluster and make sure to map ports between the Docker container and the host system, exposing well-known ports used by VMware GemFire server-side cluster processes, such as Locators and CacheServers:
Process | Port |
---|---|
HTTP |
7070 |
Locator |
10334 |
Manager |
1099 |
Server |
40404 |
Table 1. VMware GemFire Ports
Spring Boot, VMware GemFire Client Application Explained
The Spring Boot, VMware GemFire ClientCache
application we use to connect to our VMware GemFire cluster that runs in the Docker container appears as follows:
Example 5. Spring Boot, VMware GemFire Docker client application
@SpringBootApplication
@EnableClusterAware
@EnableEntityDefinedRegions(basePackageClasses = Customer.class)
@UseMemberName("SpringBootGemFireDockerClientCacheApplication")
public class SpringBootGemFireDockerClientCacheApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootGemFireDockerClientCacheApplication.class, args);
}
@Bean
@SuppressWarnings("unused")
ApplicationRunner runner(GemFireCache cache, CustomerRepository customerRepository) {
return args -> {
assertClientCacheAndConfigureMappingPdxSerializer(cache);
assertThat(customerRepository.count()).isEqualTo(0);
Customer jonDoe = Customer.newCustomer(1L, "Jon Doe");
log("Saving Customer [%s]...%n", jonDoe);
jonDoe = customerRepository.save(jonDoe);
assertThat(jonDoe).isNotNull();
assertThat(jonDoe.getId()).isEqualTo(1L);
assertThat(jonDoe.getName()).isEqualTo("Jon Doe");
assertThat(customerRepository.count()).isEqualTo(1);
log("Querying for Customer [SELECT * FROM /Customers WHERE name LIKE '%s']...%n", "%Doe");
Customer queriedJonDoe = customerRepository.findByNameLike("%Doe");
assertThat(queriedJonDoe).isEqualTo(jonDoe);
log("Customer was [%s]%n", queriedJonDoe);
};
}
private void assertClientCacheAndConfigureMappingPdxSerializer(GemFireCache cache) {
assertThat(cache).isNotNull();
assertThat(cache.getName())
.isEqualTo(SpringBootGemFireDockerClientCacheApplication.class.getSimpleName());
assertThat(cache.getPdxSerializer()).isInstanceOf(MappingPdxSerializer.class);
MappingPdxSerializer serializer = (MappingPdxSerializer) cache.getPdxSerializer();
serializer.setIncludeTypeFilters(type -> Optional.ofNullable(type)
.map(Class::getPackage)
.map(Package::getName)
.filter(packageName -> packageName.startsWith(this.getClass().getPackage().getName()))
.isPresent());
}
private void log(String message, Object... args) {
System.err.printf(message, args);
System.err.flush();
}
}
Our Customer
application domain model object type is defined as:
Example 6. Customer
class
@Region("Customers")
class Customer {
@Id
private Long id;
private String name;
}
Also, we define a Spring Data CRUD Repository to persist and access Customers
stored in the /Customers
Region:
Example 7. CustomerRepository
interface
interface CustomerRepository extends CrudRepository<Customer, Long> {
Customer findByNameLike(String name);
}
Our main class is annotated with @SpringBootApplication
, making it be a proper Spring Boot application.
We additionally annotate the main class with Spring Boot for Tanzu GemFire’s @EnableClusterAware
annotation to automatically detect the VMware GemFire cluster that runs in the Docker container and to push cluster configuration metadata from the application to the cluster as required by the application.
Specifically, the application requires that a Region called “Customers”, as defined by the @Region
mapping annotation on the Customer
application domain model class, exists on the servers in the cluster, to store Customer
data.
We use the Spring Data for VMware GemFire @EnableEntityDefinedRegions
annotation to define the matching client PROXY
“Customers” Region.
Optionally, we have also annotated our main class with Spring Boot for Tanzu GemFire’s @UseMemberName
annotation to give the ClientCache
a name, which we assert in the assertClientCacheAndConfigureMappingPdxSerializer(:ClientCache)
method.
The primary work performed by this application is done in the Spring Boot ApplicationRunner
bean definition. We create a Customer
instance (Jon Doe
), save it to the “Customers” Region that is managed by the server in the cluster, and then query for Jon Doe
using OQL, asserting that the result is equal to what we expect.
We log the output from the application’s operations to see the application in action.
Running the Spring Boot, VMware GemFire client application
When you run the Spring Boot, VMware GemFire client application, you should see output similar to the following:
Example 8. Application log output
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java ...
org.springframework.geode.docs.example.app.docker.SpringBootGemFireDockerClientCacheApplication
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)
Saving Customer [Customer(name=Jon Doe)]...
Querying for Customer [SELECT * FROM /Customers WHERE name LIKE '%Doe']...
Customer was [Customer(name=Jon Doe)]
Process finished with exit code 0
When we review the configuration of the cluster, we see that the /Customers
Region was created when the application ran:
Example 9. /Customers Region Configuration
gfsh>list regions
List of regions
---------------
Customers
gfsh>describe region --name=/Customers
Name : Customers
Data Policy : partition
Hosting Members : ServerOne
Non-Default Attributes Shared By Hosting Members
Type | Name | Value
------ | ----------- | ---------
Region | size | 1
| data-policy | PARTITION
Our /Customers
Region contains a value (Jon Doe
), and we can verify this by running the following OQL Query with gfsh:
Example 10. Query the /Customers
Region
gfsh>query --query="SELECT customer.name FROM /Customers customer"
Result : true
Limit : 100
Rows : 1
Result
-------
Jon Doe
Our application ran successfully.
Conclusion
In this chapter, we saw how to connect a Spring Boot, VMware GemFire ClientCache
application to an VMware GemFire cluster that runs in a Docker container.
Later, we provide more information on how to scale up, or rather scale out, our VMware GemFire cluster that runs in Docker. Additionally, we provide details on how you can use VMware GemFire’s Docker image with Testcontainers when you write integration tests.
Content feedback and comments