java.net.UnknownHostException during Eureka service discovery - spring-boot

According to this blog https://spring.io/blog/2015/07/14/microservices-with-spring
Was able to run the application without any issues. In this order:
java -jar microservice-demo-0.0.1-SNAPSHOT.jar registration 1111
java -jar microservice-demo-0.0.1-SNAPSHOT.jar accounts 2222
java -jar microservice-demo-0.0.1-SNAPSHOT.jar web 3333
But when trying to hit any service through the web application (http://localhost:3333/) which uses the http://ACCOUNTS-SERVICE url to access any accounts service endpoints like http://ACCOUNTS-SERVICE/accounts/123456789 I'm getting an error response:
Response Status: 500 (Internal Server Error)
Cause: org.springframework.web.client.ResourceAccessException I/O error on GET request for "http://ACCOUNTS-SERVICE/accounts/123456789": ACCOUNTS-SERVICE; nested exception is java.net.UnknownHostException: ACCOUNTS-SERVICE
When I provide the real address (http://localhost:2223/) of the accounts service to the web server instead of the http://ACCOUNTS-SERVICE everything works properly but there is no service discovery in this case.
The source code is stored at: https://github.com/paulc4/microservices-demo

This issue was due to the RestTemplate was no longer auto-created in the Brixton release-train (Spring Cloud 1.1.0.RELEASE), so the RestTemplate could not resolve properly the http://ACCOUNTS-SERVICE url using the service discovery server.
Was able to fix this issue after declaring a RestTemplate bean with #LoadBalanced as follows:
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}

Related

Jhipster Health Endpoint fails when mailserver not connected

JHipster / Spring boot provides a nice endpoint /management/health, where it aggregates health information for subsystems like db, disk, and mail.
Unfortunately, when the connection to the mail server fails, the whole endpoint fails. So you do not get information what has failed.
I get a strack trace like this:
o.s.b.a.health.MailHealthIndicator : Health check failed
com.sun.mail.util.MailConnectException: Couldn't connect to host, port: XXXX, NNNN25025; timeout -1
...
at org.springframework.boot.actuate.health.MailHealthIndicator.doHealthCheck(MailHealthIndicator.java:40)
at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:43)
at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:68)
at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:85)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getCurrentHealth(HealthMvcEndpoint.java:177)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getHealth(HealthMvcEndpoint.java:166)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(HealthMvcEndpoint.java:143)
This is spring boot 1.5.9
Where should I fix this, so that the exception is catched and instead a an error status is returned?
You have to turn on your SMTP server or disable checks to it.
To disable checks to SMTP server:
management.health.mail.enabled=false
To disable checks to all server:
management.health.defaults.enabled=false
for more information, see http://www.briansjavablog.com/2017/09/health-checks-metric-s-more-with-spring.html
I believe you can handle this error with the ExceptionHandler for 1.5.9 version of Spring Boot since the newer version there is no such problem:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(MailConnectException.class)
public ResponseEntity<?> mailExceptionHandler(MailConnectException e) {
// Do your treatment ...
} ...
}

Authentication with Spring-Boot-Admin and Eureka discovery

SBA version 2.0.1
Spring-Cloud Finchley.RELEASE
I have some services registered in Eureka. The services are Spring-Boot apps, and have their actuators secured by HTTP basic auth. The service actuators are at /actuator. The services are working and I can interact with their actuators via Postman and curl. SBA connects to Eureka and discovers the services, but they are always in a down (red) state, except for the SBA application itself, which is shown just fine as green in the SBA console, and I am able to click on it and see it's properties.
When I click on one of the service instances, I am prompted for credentials. I'm not sure what credentials to use, so I use the credentials for the service actuator. I already have these credentials in the metadata-map as shown in the docs, but I am still prompted for credentials anyway. This always results in showing the Whitelabel Error Page, with an error message like this:
Mon Jun 25 12:40:57 CDT 2018 There was an unexpected error
(type=Method Not Allowed, status=405). Request method 'POST' not
supported
Though I note the url for that error is apparently on the SBA instance intself, not the remote service. The url decodes to this: http://localhost:8080/#/instances/9207aa5fc06b/
But I see this in the log for the service, so apparently an unauthenticated request is making it to the remove service:
[2018-06-25 12:16:54.242] - DEBUG - [http-nio-8380-exec-7]
[AUTHENTICATION_SERVICE_DEV,8dc8165d4f77be7c,8dc8165d4f77be7c,false]
--- [nio-8380-exec-7] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jun 25 12:16:54 CDT 2018, status=401,
error=Unauthorized, message=Unauthorized, path=/actuator/health}] as
"application/vnd.spring-boot.actuator.v2+json" using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#30c8681]
And this in the SBA log:
2018-06-25 12:39:40.884 ERROR [SERVICES_ADMIN_CONSOLE_LOCAL,,,] 20728
--- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception
java.io.IOException: An established connection was aborted by the
software in your host machine
This is the root of my confusion, I'm not sure what credentials I need or even what I am authenticating to. I have provided the credentials to remote service in properties as well as in the login form, and it doesn't work.
When I click on the SBA application in the SBA console, it works as expected. So this seems to be related to authenticating to a remote actuator, but I can't figure out what the problem is.
Server:
#Configuration
#EnableAutoConfiguration
#EnableEurekaClient
#EnableAdminServer
public class ServiceAdmin {
public static void main(String[] args) {
SpringApplication.run(ServiceAdmin.class, args);
}
#Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
.and().csrf().disable();
}
}
}
SBA Config:
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.info.git.mode=full
management.endpoint.shutdown.enabled=true
spring.security.user.name=actuator
spring.security.user.password=password
spring.security.user.roles=ACTUATOR
eureka.instance.leaseRenewalIntervalInSeconds=10
eureka.instance.health-check-url-path=/actuator/health
eureka.instance.metadata-map.user.name=actuator
eureka.instance.metadata-map.user.password=password
eureka.client.registryFetchIntervalSeconds=5
eureka.client.serviceUrl.defaultZone=http://svcregistry1.mycompany.com/eureka/,http://svcregistry2.mycompany.com
For anyone coming to this question, being as puzzled as I, to clear up this answer.
I'm having Eureka and Springboot admin server/ui in the same application
All the services that will register into eureka AND springboot admin, will need their own /actuator credentials present as metadata :
eureka.instance.metadata-map.user.name = ${endpoints.user.name}
eureka.instance.metadata-map.user.password = ${endpoints.user.password}
This post cleared up a few things.
https://zoltanaltfatter.com/2018/05/15/spring-cloud-discovery-with-spring-boot-admin/
The problem here was I failed to understand the docs. The eureka credentials in the metadataMap have to be provided by the monitored application at registration time. Not provided in the SBA config.

spring consul services are all healthy but can't reach each other when on different hosts

Running Consul and spring-cloud-consul I have five micro services all registered and showing as healthy. Each of these services is running on a different EC2 instance.
Using the name of the micro service that is registered in consul I can't get a connection through to any of them using a RestTemplate
If Service A was to call Service B with the following code
private final static String SERVICE = "http://instance-service";
#LoadBalanced
#Autowired
private RestTemplate restTemplate;
#GetMapping("/instances")
public ResponseEntity<String> instances() {
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {
};
return restTemplate.exchange(SERVICE, HttpMethod.GET, null, reference);
}
Service A throws
2017-12-19 17:30:36.000 ERROR 1 --- [nio-8443-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://instance-service": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)] with root cause
and even with debugging set to TRACE I can see nothing coming in at all on Service B.
However if I take my identical setup and run it on a single EC2 instance everything works as expected.
All services are running in docker, but the consul agent is running on the host of each EC2 instance.
Each micro service has the following bootstrap.yml set
spring:
cloud:
consul:
config:
enabled: true
discovery:
instance-id: ${spring.application.name}
prefer-ip-address: true
If I give the RestTemplate a random endpoint it returns Unknown host so it knows the micro service is there, it's just being blocked somewhere before it hits the codebase.
How can I debug this further to find the real reason the services are getting rejected when running on different hosts?
I have tried opening all ports on the security config just to rule that out but it made no difference.
Edit: Looking at the Consul UI - I see my services are registered under the a private IP (172.18.0.2).
Should this be a public facing address?
172.18.0.2 is an ip in a a docker bridged network, you definitely want the ip address that is registered in consul to be accessible by clients that use the service discovery..
I don't know your network setup or needs but you can (some ideas, there are many) -
if you expose ports to the docker host (-p), make sure the ip of the docker host is registered for each service instance (I'm not familiar with bootstrap.yml or spring cloud)
run docker containers with --net=host
register the services in consul in different methods and outside of spring cloud's scope (API call to the consul agent, service definition file, https://github.com/gliderlabs/registrator, ...)

Getting No instance available for a microservice hosted in PCF

I have hosted 3 microservices in PCF. One is a eureka server and the other 2 are client and service microservices. The client is supposed to call the service through a rest template call and service will return a string.
I have 1 instance each of the eureka server and the client and 2 instances of the service.
I can see both my client and service registered in the Eureka dashboard. But when i try to access the service from the client[Using a rest template call] I get - 'No instances available for the [service name]'
But if i access my service directly from browser then its works fine and returns the string. But the same URL if called from a rest template returns the exception i mentioned above.
Any suggestions will help
Did you add the #LoadBalance on restTemplate bean.
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
And when calling service you have to use the service name as below.
https://SERVICENAME/restpath

How to call external non REST API from a spring cloud micro-service that use eureka to call other internal micro-service?

In our project we use Spring cloud + Eureka as service registry.
When we use the ribbon client to call internal micro-services, all URL are resolved via Eureka ... that's a problem to call external URLs.
As external API are old fashioned usage of Feign doesn't seem to be good choice.
What's the best way to call an external URL from such a service ?
Thanks in advance
Patrice
One way working:
Use two configurations.
Declare your RestTemplate Bean to call external services like this:
#Primary
#Qualifier("withoutEureka")
#Bean
public RestTemplate restTemplate(){
...
}
Inject this reference in your client this way
#Bean
public MyClientForExtCall myClientForExtCall(#Qualifier("withoutEureka")RestTemplate restTemplate)
In the other configuration use the restTemplate as usual, but don't forget to use another qualifier
#LoadBalanced
#Bean
#Qualifier("withEureka")
public RestTemplate loadBalancedEureka(){
...
}
#Bean
public MyClientForInternal myClientForInternal(#Qualifier("withoutEureka")RestTemplate restTemplate)
Patrice
You can use Ribbon without Eureka. For external APIs where you cannot configure in Eureka to abstract the discover. You can hard code their URLs in client and configure server list. The Ribbon client defaults to a configured server list, and you can supply the configuration like this:
stores:
ribbon:
listOfServers: example.com, google.com

Resources