Table of Contents
In this post, you’ll learn how to set up Spring Boot 2 applications to build a Eureka cluster for Service Registration, and how to make use of Service Discovery via clients that can get each other’s information through the Eureka Registry.
I wrote this guide because I couldn’t find too much information about how to set this entire configuration up while writing my book. I found some quick guides and valuable information in the official Spring Cloud configuration, but there were still some topics that made me struggle.
So I built an example application, available on GitHub, and accompanied it with this post to explain the code with more details. These are the topics that I’ll cover:
- How to build a Eureka Server with Peer Awareness (a Eureka Cluster) using Spring Boot 2 and Spring Cloud Netflix.
- How to connect from a Spring Boot 2 application to the Eureka Service Registry, which means how to put Service Discovery into practice.
- How to make Spring Cloud Netflix Eureka work with Docker
Quickly jump to the diagram below if you’re curious about how the system looks like.
Setting up a Service Registry with Spring Cloud Eureka
Creating a plain simple Eureka Server is easy with Spring Boot. You can go to start.spring.io and pick Spring Boot 2, the Eureka Server as a dependency and choose Maven if you want to follow my steps. This version uses Spring Boot 2.0.0 and Spring Cloud Finchley.
Open the project in your favorite editor and you just need to add an annotation to your main class, like this:
If you don’t add any configuration, you’ll get the following by default:
- The default Spring Boot
server.portproperty is 8080, so you’ll get the Eureka Service Registry available in that port. The dashboard will be accessible at
- By default, the Eureka Service Registry comes with a client behavior too. That means that it will try to register itself in a registry which, by default, is configured to be at
http://localhost:8761/eureka. To fix this problem, you can override the property carrying that value (
eureka.client.serviceUrl.defaultZone) or set your server port to 8761. However, it’s not useful to have the server registering on its own instance (since we’re in standalone mode) so we can just disable it.
I recommend you to change the port to 8761 anyways, as above. It’s set as default to that value in many configuration classes in Eureka so better use it to avoid extra configuration.
If you run this app with that first version of the configuration, the service registry will start in standalone mode (a single instance). Use your IDE or the command line to execute
mvn spring-boot:run and you’ll get a very sad, alone-in-the-world service registry. You can navigate with your browser to http://localhost:8761 to check the Eureka Dashboard (we’ll have a look at it later).
This dashboard lists the DS replicas (registry peers) and the registered clients (none, thus far). You can ignore the fact that the own server is listed as an unavailable replica (also part of some default configuration).
Let’s quickly move on, this is just plain simple configuration. Let’s do something more interesting.
Eureka Registry Cluster via enabling Peer Awareness
What if we want to use the Peer Awareness feature that comes with the Eureka Service Registry? Basically, we’d like to have two registry instances that can share with each other the contents of the registry (the registered clients) so we implement resiliency. To prove that this works, later we’ll register a client in each registry and check if those clients can find each other contacting the instance that they know. See the figure for a better understanding of the scenario.
For now, we aim to have two Eureka Service Registry instances that can share the registry information: a Eureka Cluster (a.k.a. the Replica mode in Eureka). To achieve this, we need to take into account some very important concepts about how the Eureka Replica mode works:
- The Replica mode will NOT work if you use the same hostname in both instances. That means that you need to give your host two different aliases if you want to test this within the same host.
- The Replica mode will NOT work if you use different application names in both instances. It makes sense since the application itself is the same, it’s just that we’re replicating it.
- The magic behind the Replica mode is as simple as configuring each instance to register in another one. You can extend this to as many instances as you like, as long as you keep connecting all the edges (A registers in B, B registers in C, C registers in A). In our case, it’s just crossing both of them.
Having that in mind, we can use two different Spring Boot profiles for a better-organized configuration.
Let’s review this configuration:
- There is a common part applicable to both profiles – the part above the first
---. This is optional, but I prefer to declare two properties to quickly find the exposed ports (
tpd.peerNPort). They are used in the profiles. Also, I’ve configured Spring Boot Actuator to expose the
/infoendpoints from the root context. This is a good idea in general but, besides that, the Eureka Dashboard creates links to each registered service pointing to these endpoints so you need to configure this if you want them to work (although is a mere aesthetic detail). If you want to use these endpoints, don’t forget to add the
spring-boot-starter-actuatordependency to the
- Note that in this file it’s also configured the
/shutdownendpoint and exposed it via web. This is for educational purposes, don’t do this in production :). You can use it later to kill one of the server replicas and see how the peer still has the full registry contents.
- The first profile,
peer1, exposes the server on the port 8761, uses the host
eureka-peer1and the common application name:
eureka-cluster. You can use the property
spring.application.nameinstead, that will also work.
- The second profile,
peer2, uses the port 8762, a hostname
eureka-peer2and the common
- Pay attention to the
eureka.client.serviceUrlproperty. We create a
defaultZonekey in each instance pointing to the other peer (peer2 registers on peer1, and vice-versa).
- If you wonder where the
/eurekacontext is coming from I tell you that this is hard-coded in a hidden corner of the Eureka implementation. The fact is that you need it since the REST API of the registry is located there and otherwise they won’t see each other.
Before you execute this application you need an extra step though. As pointed out before, the Peer Awareness feature won’t work if you use the same hostname. We set them to
eureka-peer2 in our configuration, but we need to redirect those aliases to our real local host for that to work on our machine.
- In windows, you need to modify your
hostsfile and add a couple of lines like these (note that you usually need administrator privileges and save the file without adding an extension, you can find more info here):
- In Linux or Mac, you need to add the same lines, but this time in your
/etc/hostsfile (more info on the same link).
Now you can run two times this application, again from your preferred IDE or from the command line, using for each execution a different profile:
Once they are up and running, navigate with your browser to
http://localhost:8762 respectively. You’ll see the Dashboard showing this time both replicas and where to find them, and also listing them as available.
If you’re getting your Eureka instance as an ‘unavailable replica’, it might be due to one of these reasons:
- You didn’t use the same application name in both instances (pay attention to the EUREKA-CLUSTER in the screenshot, what do you see?).
- You didn’t use the context
/eurekain your defaultZone URLs.
- You are using the same hostname for both instances (e.g. localhost). Remember that they must be different.
- The hostnames can’t be mapped by your computer (did you include them in your hosts file?).
Now that we have our Eureka Cluster, let’s use it to register some dummy clients and see how Service Discovery with Eureka and Peer replication works.
Registering Eureka Clients
To see Eureka in action and demonstrate that everything is working as expected, we’ll create two Spring Boot applications, each one registering in only one of the instances of the Eureka cluster. We want to prove that the cluster will replicate the registry entries so, in our example, these micro-apps will be able to see each other by using their application alias.
If you want to start from scratch, go to start.spring.io and choose Spring Boot 2, Maven and Eureka Discovery and Web as dependencies. Otherwise, just clone the repository available on GitHub.
Then we create two different controllers for two different profiles in our client application:
english. The idea is that we have two apps communicating with each other:
- When the
HolaControllerprocesses a request to
http://localhost:8084/hola, it will try to reach
http://tpd-en/hello-serverto get an English greeting and concatenate it with its own.
HelloControllerwill do the other way around. It’s accessible for us at
http://localhost:8085/hello, and will build a greeting concatenating the result from the Spanish instance at
We use Service Discovery here for the clients to be able to resolve those aliases:
tpd-es (localhost:8084) and
tpd-en (localhost:8085). This is the implementation of the Spanish controller:
As you can imagine, the implementation of the HelloController class is symmetric to this one. We can inject here the
EurekaClient bean since it’s loaded in the context just by having the Eureka client dependency in our classpath. Then, we use it to resolve the name of the fixed virtual alias (tpd-en) to the real location of the instance. The logic behind that call will contact the Service Registry (if it hasn’t been previously fetched) and ask for the resolution of the virtual name.
This client instance is connected to just one of the instances of the Service Registry but, given that we set up the Peer Awareness, that registry instance will contain the mapping of both clients. Let’s have a look at the configuration of the client:
- The common configuration sets the property
eureka.instance.lease-renewal-interval-in-secondsto 10 seconds, replacing the default value of 30 seconds. This is completely optional, I normally change it to have clients renewing their lease with the server in a faster way, which is more useful when you’re testing the configuration values.
- Hanging from
tpd.configI’ve extracted some property values like each instance’s port, the server URLs and the virtual aliases to use. These are used in the profiles below.
- As detailed above, the
spanishprofile sets the application name to the virtual alias (so it will be registered like that in the Eureka Registry). Note that the
service-urlproperty is set to the server’s peer1 instance, whereas the
englishclient instance (identified by the second profile) connects to the server’s peer2 instance.
Eureka Server Cluster in Action
Time to play with the applications! You can use your IDE to run the four applications but I’ll give you also the instructions to do that from the command line.
Within the eureka-server-example folder, run these commands in two different terminals:
And now, the client instances, which are also two different commands to run the same application:
In the background, these four Spring Boot application instances will start communicating with each other thanks to Eureka and our fine-tuned configuration:
- The server instances will register on each other and then synchronize their registries.
- The client instances will register each one on one registry instance, causing them to synchronize their registries again.
Navigate with your browser to one of the Registry instances to very that everything went as expected. You should see something like this:
Finally, if you do a GET request to our exposed endpoints for each client instance (also with your browser, or you can go for
http if you know how), you’ll see how our Eureka plumbing works perfectly. For example, if you request
Getting a 500 error instead? You impatient! Give Eureka some extra time to register the clients and propagate the registry contents.
Bear in mind that, in order to demonstrate that Peer Awareness works, we didn’t use the optimal configuration here. To really achieve resilience, each client should know how to fetch both registries, so our final setup for a production-ready system should specify both instances in the clients (like shown below). However, if we would have done from the beginning, the registry replication wouldn’t have been so obvious to us.
Great! You just learned how to set up Service Discovery with Resiliency using Eureka and Spring Boot. Of course, there is much more to learn in terms of Microservices Architecture with Spring Boot and Spring Cloud, like how to use Load Balancing or a Circuit Breaker in this scenario. Also, an API Gateway will be useful if we want to have the same entry point from our browser to access /hello and /hola. If you want to learn all these topics from a practical perspective, have a look at my book Learn Microservices with Spring Boot, I’m sure you’ll enjoy the step-by-step approach used there.
Liked this guide? Then you can star the code on GitHub or leave a comment here, thanks!
Bonus: Docker configuration
If you want to run this example architecture, you can also do it using Docker. First, you need to generate the jar files by executing
mvn clean package in both client and server folders. After that, go to the docker folder in the repository and execute:
The images will be built and then executed as containers. Note that you don’t need to assign host aliases in this case since that’s now managed by Docker. Enjoy it!