I have set up Zuul for routing and Eureka for service discovery, which works fine. Before setting up Eureka, I used server.address=127.0.0.1 to bind my actual service to localhost so that they could only be accessed from within the Api gateway.
When combining Zuul and Eureka, server.address=127.0.0.1 does not work anymore. I cannot access my actual REST endpoints, neither from within my network nor from the outside.
application.properties of my Eureka service discovery:
spring.application.name=service-discovery
server.port=8761
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
application.properties of my Zuul API gateway:
spring.application.name=api-gateway
zuul.prefix=/api
server.port=8080
ribbon.eureka.enabled=true
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
zuul.routes.library.path=/library/**
zuul.routes.library.serviceId=library
application.properties of my actual REST service:
spring.application.name=library
server.servlet.context-path=/library
server.port=8090
server.address=127.0.0.1
ribbon.eureka.enabled=true
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
When I remove server.address=127.0.0.1 from the REST service's properties file, I can of course access the resource - But also from without localhost, which is not what I want.
So what I try to achieve is that my little microservices can only be accessed from within localhost (after the request has passed the Zuul API gateway). Furthermore I want to use Eureka for service discovery and for having the chance to provide second instances of serives.
Registering the actual microservices with eureka.instance.hostname=localhost or eureka.instance.ip-address=127.0.0.1 to the Eureka server, combined with a binding of the microservice to localhost (server.address=127.0.0.1) did the job.
These are the application.properties files:
application.properties of my Eureka service discovery:
spring.application.name=service-discovery
server.port=8761
server.address=127.0.0.1
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
application.properties of my Zuul API gateway:
spring.application.name=api-gateway
zuul.prefix=/api
server.port=8080
ribbon.eureka.enabled=true
eureka.client.registerWithEureka=false
zuul.routes.library.path=/library/**
zuul.routes.library.serviceId=library
zuul.routes.library.stripPrefix=false
application.properties of my actual REST service:
spring.application.name=library
server.servlet.context-path=/library
server.port=8090
server.address=127.0.0.1
ribbon.eureka.enabled=true
eureka.client.registerWithEureka=true
eureka.instance.hostname=localhost
eureka.instance.ip-address=127.0.0.1
The "library" microservice is now only available from localhost but still registered at Eureka and behind the Zuul API gateway.
Related
In Spring Boot Microservices architecture, we generally register our each microservice (its many instances) into Eureka server by doing eureka.client.register-with-eureka=true, eureka.client.fetch-registry=true and eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka. So Eureka acts as service registry for these services (service-name, hostname and its IP).
Spring Cloud API Gateway acts as a single point of entry for any microservice call. It can work as a proxy service to route a request to the concerned microservice, abstracting the producer details. It has route information only, then how Spring Cloud API gateway comes to know which microservice instance to call to? How API Gateway and Eureka communicates and load balance?
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/users/**
- id: order-service
uri: lb://department-service
predicates:
- Path=/departments/**
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
With the Discovery Locator enabled in API Gateway, you do not have to manually configure the routes unless absolutely needed.
The way API Gateway knows which Eureka Service to route the incoming request to is as follows:
Assuming,
Orders Service runs on http://localhost:8080
API Gateway runs on http://localhost:8082
Eureka Service name for Orders Service - order-service
Then if order-service getOrders endpoint: http://localhost:8080/orders, then with Discovery Locator enabled the request needs to be routed through the API gateway with the following URL: https://localhost:8082/order-service/orders, i.e., {ApiGatewayHost}/{EurekaServiceId}/{ActualEndpoint}.
Register Gatway to Eureka Server
I have configured my spring boot application monitor-client to register to Eureka. I have a separate spring boot admin (SBA) application monitor that monitors all applications registered to Eureka.
If the context-path is not set in my application, everything is working fine. However if the context-path is set, SBA does not show correct information anymore. From the documentation it seems that I need to update the metadata properties of Eureka which I have done.
My monitor application is configured as follows:
application.properties:
spring.application.name=monitor-client
server.servlet.context-path=/monitor-client
server.port=9876
# Monitoring config
management.endpoints.web.exposure.include=*
eureka.instance.metadataMap.management.context-path=/monitor-client/actuator
My application is showing as 'offline' but I can browse all the details in the 'insight' tab. I suppose SBA correctly access the actuator endpoints but incorrectly uses the /health endpoint and I do not understand how that is possible?
If I go to the administration interface of SBA, I notice that the wrench endpoint and the health endpoint are not the same:
localhost:9876/monitor-client/actuator (wrench)
localhost:9876/actuator/health (health)
I've fiddled around with some settings but between the managment settings, the actuator settings and the eureka settings, I'm not sure which one is to be configured for this to work.
I've tried:
management.endpoints.web.base-path
eureka.instance.health-check-url-path
I'm currently using spring boot 2.1.2.RELEASE and matching version of SBA
Can you try with these configuration
server:
servlet:
context-path: /monitor-client
#management config
eureka:
instance:
health-check-url-path: /actuator/health
metadata-map:
management.context-path: /monitor-client/actuator
client:
serviceUrl:
defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
management:
endpoint:
health:
show-details: always
endpoints:
web:
base-path: /actuator
exposure:
include: "*"
I'm starting with spring cloud.
I created 3 application, one is for discovery service, one for gateway and one is a service.
I'm not using actually spring cloud config and any load balacing
For my discovery
server.port=8761
spring.application.name=discovery-service
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
For my gateway
#Port for Registry service
server.port=8080
spring.application.name=gateway-service
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.routes[0].id=hostel-service
spring.cloud.gateway.routes[0].uri=lb://hostel-service
spring.cloud.gateway.routes[0].predicates[0]=Path=/hostels/**
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
For my hostels service
server.port=9000
spring.application.name=hostel-service
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
I see then hostel service is registered in the discovery service
Registered instance HOSTEL-SERVICE/192.168.102.129:hostel-service:9000
with status UP (replication=false)
See it to when i go to http://localhost:8761/
When I try to call
http://localhost:8080/hostels
or
http://localhost:8080/hostel-service/hostels
I get a 404 error
If I do
http://localhost:9000/hostels
I get good results
Edit
Code on github
https://github.com/mctdi/hostel
https://github.com/mctdi/gateway
https://github.com/mctdi/discovery
The hostels app registers in Service Discovery, but the gateway app doesn't. Add 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' to you implementation dependencies in build.gradle - it will then register in Eureka and the http://localhost:8080/hostels request will be routed to the hostels app.
Through reading various books / tutorials, it appears that it is possible to auto-configure routes in Zuul when using it in combination with Eureka service discovery. That means that I don't have to explicitly add routes to Zuul's application.properties.
So I understand this correctly? Or do I still need to add routes explicitly to Zuul in order it to work as a gateway?
I would like it to automatically create routes from the application name's that are registered with Eureka. Is this possible?
(Note: I have actually tried this, but when I go to http://localhost:8762/routes I just get an error page.)
Sure. In most microservices implementations, internal microservices endpoints are not exposed outside. A set of public services will be exposed to the clients using an API gateway.
The zuul proxy internally uses the Eureka Server for service discovery.
I would like it to automatically create routes from the application name's that are registered with Eureka. Is this possible?
Sure. I will show you gateway example.
1. Create your service project (user-service)
create application.properties file
# --- Spring Config
spring:
application:
name: OVND-USER-SERVICE
# Eureka client
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URL:http://localhost:8761/eureka/}
2. Setting up Zuul project (Gateway-service)
1.#EnableZuulproxy to tell Spring Boot that this is a Zuul proxy
#SpringBootApplication
#EnableZuulProxy
#EnableDiscoveryClient
public class GatewayServiceApplication {
2.create an application.properties file
# =======================================
# Gateway-service Server Configuration
# =======================================
# --- Spring Config
spring:
application:
name: gateway-service
server:
port: ${PORT:8080}
# Eureka client
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URL:http://localhost:8761/eureka/}
zuul:
host:
routes:
## By default, all requests to user service for example will start with: "/user/"
## What will be sent to the user service is what comes after the path defined,
## So, if request is "/user/v1/user/tedkim", user service will get "/v1/user/tedkim".
user-service:
path: /user/**
service-id: OVND-USER-SERVICE
another-service:
path: /another/**
service-id: OVND-ANOTHER-SERVICE
Eureka website ( localhost:8761 )
Yes. You can integrate Zuul with Eureka and configure the routes based on application names registered in Eureka. Just add the following configuration to Zuul application:
zuul:
ignoredServices: "*"
routes:
a-service: /a-service/**
b-service: /b-service/**
c-service: /c-service/**
d-service: /d-service/**
I have some web services registered at Spring Boot Eureka Server. Is there any way I can check the endpoints registered at Eureka Server, with respect to all the application?
e.g: Eureka server
Service1 means Request will be routed to service endpoint: localhost:9080/service1
Service2 means Request will be routed to service endpoint: localhost:9088/service2
Service3 means Request will be routed to service endpoint: localhost:9085/service3
You can check the Eureka dashboard at http://host-name:8761 (Change the port if you're using a different one).
Secondly, Eureka doesn't route any request. It is just a service registry and keeps the records of the Microservices and its instances. You need an API Gateway (ZUUL) or similar to do the routing along with client side load balancers (ribbon, etc.).
You can configure the zuul endpoints in the application.yml (or properties) file like below to access your service endpoints.
zuul:
ignoredServices: "*"
routes:
service1:
path: /service1/**
service2:
path: /service2/**
If you want to access the service1, then your endpoint will be something like http://localhost:8765/service1/{custom-path}
Note: 8765 is the default zuul port. Change it accordingly.