I am evaluating building microservices using Spring Boot and Spring Cloud (Zuul and Eureka) running in separate docker containers, deployed in separate Amazon EC2 instances.
I have a simple REST service that registers with Eureka, and have configured Zuul to route requests to this service by looking it up in Eureka.
I can get this to work running locally (i.e. not in Amazon/EC2) on my Mac using boot2docker, but when deployed on EC2, Zuul cannot find the service, and reports a 'Forwarding error' (status 500).
In EC2, everything is configured to run on port 80 (just while evaluating so I can easily access through our firewall). I can see both Zuul and my service in the Eureka system status page (although none of the links work!).
The clients are configured to find Eureka with a full AWS domain name, so I can see how they find Eureka OK. e.g.
client:
serviceUrl:
defaultZone: http://ec2-XX-XX-XX-XX.ap-southeast-2.compute.amazonaws.com:80/eureka/,http://ec2-YY-YY-YY-YY.ap-southeast-2.compute.amazonaws.com:80/eureka/
But, the clients seem to be registering themselves with their internal docker IP address (based on the Eureka system status links).
The edgeserver link points to http://172.17.0.2/info The trialservice link points to http://172.17.0.3/info
I'm guessing this is incorrect and that other EC2 instances don't know to get to this address.
I've read this page https://github.com/Netflix/eureka/wiki/Configuring-Eureka-in-AWS-Cloud which suggests using AWS EC2 Elastic IP addresses, but I was hoping I wouldn't have to do this.
I've also seen there is a current discussion around this subject here, https://github.com/spring-cloud/spring-cloud-netflix/issues/432
Has anyone managed to get this type of setup working, and if so, how did they configure the Eureka properties?
Each request received by Zuul is forwarded to a different instance in a round robin fashion. If we start another instance and register it in Eureka, Zuul will register it automatically and start forwarding requests to it: Hello from 'SPRING-CLOUD-EUREKA-CLIENT with Port Number 8083'!
Zuul acts as the API gateway, providing a uniform, single point of entry into the set of microservices, while Eureka is essentially used as a “meta data” transport. Each client application instance (read microservice) registers its instance information (location, port, etc.) with the Eureka server.
Creating Zuul Server ApplicationAdd the @EnableZuulProxy annotation on your main Spring Boot application. The @EnableZuulProxy annotation is used to make your Spring Boot application act as a Zuul Proxy server. You will have to add the Spring Cloud Starter Zuul dependency in our build configuration file.
OK, to answer my own question, I've found a solution. It basically involves configuring eureka to use the hostname and docker to use the net=host option.
Here is my setup (just showing setup for one availability zone):
application.yml:
Zuul:
spring:
profiles: aws
server:
port: 80
eureka:
datacenter: cloud
instance:
preferIpAddress: false
client:
serviceUrl:
defaultZone: http://ec2-XX-XX-XX-XX.ap-southeast-2.compute.amazonaws.com:80/eureka/
Eureka:
spring:
profiles: aws-discoA
server:
port: 80
eureka:
instance:
preferIpAddress: false
datacenter: cloud
enableSelfPreservation: false
client:
name: eureka
preferSameZone: false
shouldOnDemandUpdateStatusChange: false
region: default
serviceUrl:
defaultZone: http://ec2-YY-YY-YY-YY.ap-southeast-2.compute.amazonaws.com:80/eureka/
Service:
spring:
profiles: aws
server:
port: 0 # or 80 if there is only 1 service/docker in this EC2
eureka:
datacenter: cloud
instance:
preferIpAddress: false
client:
serviceUrl:
defaultZone: http://ec2-XX-XX-XX-XX.ap-southeast-2.compute.amazonaws.com:80/eureka/
I'm not sure if "datacenter: cloud" is needed?
Then to launch each:
Zuul
sudo docker run -d --name edge -e JAVA_TOOL_OPTIONS="-Dspring.profiles.active=aws -Deureka.instance.hostname=$HOSTNAME" --net="host" edge
Eureka
sudo docker run -d --name discovery -e JAVA_TOOL_OPTIONS="-Dspring.profiles.active=aws-discoA -Deureka.instance.hostname=$HOSTNAME" --net="host" discovery
Service
sudo docker run -d --name service -e JAVA_TOOL_OPTIONS="-Dspring.profiles.active=aws -Deureka.instance.hostname=$HOSTNAME" --net="host" service
Just to ensure this works in a more complex setup, I configured more servers, some with multiple dockers per EC2 and now have the following setup.
This setup is duplicated in two availability zones with a load balancer in front of the Zuul servers. Each service has an endpoint that just returns its name, hostname, port and the number of times it has been called.
I can then hit the load balancer and see each service being called as the AWS load balancer and Ribbon load balancers cycle through the services.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With