DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Using Spring Cloud Gateway and Discovery Service for Seamless Request Routing
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Microservices With JHipster
  • NGINX With Eureka Instead of Spring Cloud Gateway or Zuul

Trending

  • It’s Not About Control — It’s About Collaboration Between Architecture and Security
  • Apache Doris vs Elasticsearch: An In-Depth Comparative Analysis
  • Beyond Linguistics: Real-Time Domain Event Mapping with WebSocket and Spring Boot
  • A Modern Stack for Building Scalable Systems
  1. DZone
  2. Software Design and Architecture
  3. Microservices
  4. Microservices Discovery With Eureka

Microservices Discovery With Eureka

In this article, let's explore how to integrate services discovery into a microservices project.

By 
Jennifer Reif user avatar
Jennifer Reif
DZone Core CORE ·
Jan. 22, 23 · Tutorial
Likes (8)
Comment
Save
Tweet
Share
11.5K Views

Join the DZone community and get the full member experience.

Join For Free

Gaining complexity in a microservices system certainly isn't for the faint of heart (though neither is complexity in monoliths!). When there are many services that need to communicate with one another, we might need to coordinate multiple services communicating with multiple other services. We also might code for varying environments such as local, development server, or the cloud.

How do services know where to find one another? How can we avoid problems when a service is unavailable? How do we handle requests when we scale up or down certain parts of our system?

This is where something like Spring Cloud Netflix Eureka comes into play. Eureka is a service discovery project that helps services interact with one another without hardwiring in instance-specific or environment-dependent details.

Architecture

We have carefully built up a system of microservices from generic application chatter to a system of services communicating among one another. In the last article, we migrated most of our standalone services into Docker Compose so that it could orchestrate startup and shutdown as a unit.

In this article, we will add a service discovery component, so that services can find and talk to one another without hard-coding host and port information into applications or environments.

Docker Compose manages most of the services (in dark gray area), with each containerized service encompassed in a light gray box. Neo4j is the only component managed externally with Neo4j's database-as-a-service (AuraDB). Interactions between services are shown using arrows, and the types of data objects passed to numbered services (1-4) are depicted next to each.

Spring Cloud Netflix Eureka

Spring Cloud Netflix originally contained a few open-sourced projects from Netflix, including Eureka, Zuul, Hystrix, and Ribbon. Since then, most of those have been migrated into other Spring projects, except for Eureka.

Eureka handles service registry and discovery. A Eureka server is a central place for services to register themselves. Eureka clients register with the server and are able to find and communicate with other services on the registry without referencing hostname and port information within the service itself.

Config + Eureka Architecture Decision

I had to make a decision on architecture when using Spring Cloud Config and Eureka together in a microservices system. There are a couple of options:

1. Config-first approach. Applications (services1-4) will reach out to config server first before gathering up other properties. In this approach, the config server does not register with Eureka.

2. Discovery-first approach. Applications will register with Eureka before connecting to config and gathering properties. In this approach, config server becomes a Eureka client and registers with it.

There is an excellent blog post that provides a clear explanation of each, along with pros and cons. I'd highly encourage checking that out!

I opted for the config-first approach because there is already a bit of delay starting up applications in Docker Compose (see blog post detailing this). Going with discovery-first would mean an extra step in the chain before applications could connect to config and contact databases. Since I didn't want to slow this step down any further, I decided not to register the config server app with Eureka, leaving it separate.

Without further ado, let's start coding!

Applications: Eureka Server

We will use the Spring Initializr at start.spring.io to set up the outline for our Eureka server application.

On the form, we choose Maven for the Project, then leave Language and Spring Boot version fields defaulted. Under the Project Metadata section, I updated the group name for my personal projects, but you are welcome to leave it defaulted. I named the artifact eureka-server, though naming is up to you, as long as we map it properly where needed. All other fields in this section can remain as they are. Under the Dependencies section, we need only Eureka Server. Finally, we can click the Generate button at the bottom to download the project.

The project will download as a zip, so we can unzip it and move it to our project folder with the other services. Open the project in your favorite IDE and let's get coding!

The pom.xml contains the dependencies and software versions we set up on the Spring Initializr, so we can move to the application.properties file in the src/main/resources folder.

Properties files
 
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

We need to specify a port number for this application to use so that its traffic doesn't conflict with our other services. The default port for Spring Cloud Eureka server is 8761, so we will use that. Next, we don't need to register the server itself with Eureka (useful in systems with multiple Eureka servers), so we will set the eureka.client.register-with-eureka value to false. The last property is set to false because we also don't need this server to pull the registry from other sources (like other Eureka servers). A StackOverflow question and answer addresses these settings well.

In the EurekaServerApplication class, we only need to add the annotation @EnableEurekaServer to set this up as a Eureka server.

Let's test this locally by starting the application in our IDE and navigating a web browser window to localhost:8761. This should show us a page like the one below, which gives details about the server and a section for Instances currently registered with Eureka. Since we haven't connected any other services with Eureka, we don't have any services registered with the server.

That's it for the server, so let's start retrofitting our other services as Eureka clients.

Applications: Service1

We don't have many changes to add for Spring Cloud Eureka. Starting in the pom.xml, we need to add a dependency.

XML
 
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

This dependency enables the application as a Eureka client. Most recommendations would also have us adding an annotation like @EnableEurekaClient (Eureka-specific) or @EnableDiscoveryClient (project-agnostic) to the main application class. However, that is not a necessary requirement, as it is defaulted to enabling this functionality when you add the dependency to the pom.xml.

To run the service locally, we will also need to add a property to the `application.properties` file.

Properties files
 
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

This tells the application where to look for the Eureka server. We will move this property to the config server file for this application, so we can comment this one out when we test everything together. However, for testing a siloed application, you will need it enabled here.

Let's start on changes to service2, which interacts with service1.

Applications: Service2

Just like with service1, we need to add the Eureka client dependency to service2's pom.xml to enable service discovery.

XML
 
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

We also want to have this application use Spring Cloud Config for referencing the Eureka server, so we can retrofit that by adding the dependency. We will walk through the config file changes in a bit.

Again, if we test locally, we would also need to add the following property to the application.properties file.

Properties files
 
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka

Since we will test everything together, it is commented out in the application for now. Instead, we will add a properties file for Spring Cloud Config to host, similar to our other services (next section).

Next, we need to make some adjustments to the main application class to utilize Eureka over previously-defined hostname and port locations.

Java
 
public class Service2Application {
    public static void main(String[] args) {
        SpringApplication.run(Service2Application.class, args);
    }

    @Bean
    @LoadBalanced
    WebClient.Builder createLoadBalancedBuilder() { return WebClient.builder(); }

    @Bean
    WebClient client(WebClient.Builder builder) { return builder.baseUrl("http://mongo-client").build(); }
}

Eureka lets calling applications reference an application name, and it will map the hostname/port details behind-the-scenes, no matter where the application is running. This is where we see the mongo-client referenced in the second @Bean definition (11th line of above code).

We also need to create a load-balanced bean (only required when using Eureka). Step-by-step, I created a WebClient.Builder bean, load balanced it with the @LoadBalanced annotation, then used that to create the actual WebClient bean that gets injected for use in method calls (in the BookController class).

Applications: Service3 and Service4

Next, we need to add our other services to Eureka using the steps below.

1. Add the dependency to each pom.xml file.

2. For local testing, add the commented out property in the application.properties file.

Now let's add the Eureka property to the Spring Cloud Config files for our applications!

Spring Cloud Config

For each config file the server hosts, we will need to add the following:

YAML
 
eureka:
  client:
    serviceUrl:
      defaultZone: http://goodreads-eureka:8761/eureka

This tells the application where to look so it can register with Eureka. Full sample code for each config file is located in the related Github repository folder.

We also need to create a whole new config file for service2 to use the config server.

YAML
 
spring:
  application:
    name: goodreads-client

eureka:
  client:
    serviceUrl:
      defaultZone: http://goodreads-eureka:8761/eureka

A sample is provided on the Github repository, but this file is created in a local repository initialized with git, and then referenced in the config server properties file for that project to serve up. More information on that is in a previous blog post.

Let's make a few changes to the docker-compose.yml!

docker-compose.yml

We need to remove the dynamic environment property for service2 and to add the Eureka server project for Docker Compose to manage.

YAML
 
goodreads-svc2:
    #other properties...
    environment:
      - SPRING_APPLICATION_NAME=goodreads-client
      - SPRING_CONFIG_IMPORT=configserver:http://goodreads-config:8888
      - SPRING_PROFILES_ACTIVE=docker

We added environment variables for application name, config server location, and spring profiles like we see in our other services.

Next, we need to add our Eureka server application to the compose file.

YAML
 
goodreads-eureka:
    container_name: goodreads-eureka
    image: jmreif/goodreads-eureka
    ports:
      - "8761:8761"
    environment:
      - EUREKA_CLIENT_REGISTER-WITH-EUREKA=false
      - EUREKA_CLIENT_FETCH-REGISTRY=false
    volumes:
      - $HOME/Projects/docker/goodreads/config-server/logs:/logs
    networks:
      - goodreads

For our last step, we need to build all of the updated applications and create the Docker images. To do that we can execute the following commands from the project folder:

Shell
 
cd service1
mvn clean package -DskipTests=true
cd ../service2
mvn clean package -DskipTests=true
cd ../service3
mvn clean package -DskipTests=true
cd ../service4
mvn clean package -DskipTests=true
cd ../eureka-server
mvn clean package

Note: the Docker Compose file is using my pre-built images with Apple silicon architecture. If your machine has a different chip, you will need to do one of the following: 1) utilize the build option in the docker-compose.yml file (comment out image option), 2) create your own Docker images and publish to DockerHub (plus modify the docker-compose.yml file image options).

We can run our system with the same command we have been using.

Shell
 
docker-compose up -d

Note: If you are building local images with the `build` field in docker-compose.yml, then use the command `docker-compose up -d --build`. This will build the Docker containers each time on startup from the directories.

Next, we can test all of our endpoints.

  • Goodreads-config (mongo): command line with curl localhost:8888/mongo-client/docker.
  • Goodreads-eureka: web browser with localhost:8761 and note the applications (might take a few minutes for everything to register).
  • Goodreads-svc1: command line with curl localhost:8081/db, curl localhost:8081/db/books, and curl localhost:8081/db/book/623a1d969ff4341c13cbcc6b.
  • Goodreads-svc2: command line with curl localhost:8080/goodreads and curl localhost:8080/goodreads/books.
  • Goodreads-svc3: curl localhost:8082/db, curl localhost:8082/db/authors, and curl localhost:8082/db/author/623a48c1b6575ea3e899b164.
  • Goodreads-config (neo4j): command line with curl localhost:8888/neo4j-client/docker.
  • Neo4j database: ensure AuraDB instance is running (free instances are automatically paused after 3 days).
  • Goodreads-svc4: curl localhost:8083/neo, curl localhost:8083/neo/reviews, and curl localhost:8083/neo/reviews/178186 or web browser with only URL.

Bring everything back down again with the below command.

Shell
 
docker-compose down

Wrapping Up!

In this iteration of the project, we integrated service discovery through the Spring Cloud Netflix Eureka project. We created a Eureka server project, and then retrofitted our other services as Eureka clients with an added dependency.

Finally, we integrated the new Eureka server project to Docker Compose and updated some of the options for the other services. We tested all of our changes by spinning up the entire microservices system and checking each of our endpoints.

Keep following along in this journey to find out what comes next (or review previous iterations to see what we have accomplished). Happy coding!

Resources

  • Github: microservices-level10 repository
  • Blog post: Baeldung's guide to Spring Cloud Netflix Eureka
  • Blog post: Config First vs. Discovery First
  • Documentation: Spring Cloud Netflix
  • Interview questions: What is Spring Cloud Netflix?
CURL Service discovery Spring Cloud YAML microservice

Opinions expressed by DZone contributors are their own.

Related

  • Using Spring Cloud Gateway and Discovery Service for Seamless Request Routing
  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • Microservices With JHipster
  • NGINX With Eureka Instead of Spring Cloud Gateway or Zuul

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!