Spring Boot admin not showing any client applications in dashboard - spring-boot-admin

I have been following this tutorial for Spring boot Admin, but when I run the admin application I can't see any spring boot client application for monitoring. I have checked that both the admin and client apps are running. Admin is running on port 8080 and client application is running on port 9010
This is what I have done in my Admin application
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
<version>1.5.3</version>
</dependency>
Added these annotations
#Configuration
#SpringBootApplication
#EnableAdminServer
public class SpringBootAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootAdminApplication.class, args);
}
}
This is what I have added in my client application
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>1.5.3</version>
</dependency>
and added this in my properties file (YAML)
spring:
boot:
admin:
url:
- http://localhost:8080
management:
security:
enabled: false
This is what my Dashboard looks like, as you can see there are no applications to monitor.

Related

Difference in load balancer behavior

I noticed that load balancer has different behavior pattern in certain scenario.
When using discovery with load balancer and one of the services is restarted on different port - then if services are running on Spring Boot 2.3.8-RELEASE, other service can find and communicate with restarted service, but if services are running on Spring Boot 2.7.8 it will only work if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
I tried to create 3x brand new projects in first test using Spring Boot 2.3.8-RELEASE and in second test Spring Boot 2.7.8 to eliminate any specific setting or configuration or my actual project. I was thinking that maybe there is something specific in my actual project causing difference in behavior, but it turns out that vanilla plain setup has exactly this same problem.
In general my expectation was that setup using Spring Boot 2.3.8-RELEASE will have exactly this same behavior in case of restarting a service on different port as Spring Boot 2.7.8 - but that doesn't seems to be a case.
I noticed that load balancer has different behavior pattern in certain scenario.
When using discovery with load balancer and one of the services is restarted on different port - then if services are running on Spring Boot 2.3.8-RELEASE, other service can find and communicate with restarted service, but if services are running on Spring Boot 2.7.8 it will only work if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
I tried to create 3x brand new projects in first test using Spring Boot 2.3.8-RELEASE and in second test Spring Boot 2.7.8 to eliminate any specific setting or configuration or my actual project. I was thinking that maybe there is something specific in my actual project causing difference in behavior, but it turns out that vanilla plain setup has exactly this same problem.
In general my expectation was that setup using Spring Boot 2.3.8-RELEASE will have exactly this same behavior in case of restarting a service on different port as Spring Boot 2.7.8 - but that doesn't seems to be a case.
Here are details of my tests.
My setup is 3x spring boot applications - all in this same version (first test with 2.3.8-RELEASE and second with 2.7.8):
Discovery service - Eureka Server
Test service 1 - "caller" - Eureka Client
Test service 2 - "receiver" - also Eureka Client
The difference in behavior can be reproduce following scenario:
Start Discovery service
Start "caller" application - wait for it to register in Discovery
Start "receiver" application - also wait for it to register in Discovery and also wait for "caller" application to fetch latest record from Discovery
Call GET endpoint in "caller" application which in turn calls GET endpoint in "receiver" application
At this stage everything works fine, "caller" can find and call "receiver"
Change server port in "receiver" application to different value and restart "receiver" application
Again, wait for "receiver" application to register in Discovery and "caller" application to fetch latest record from Discovery
At this stage there is a difference in the way how Spring Boot 2.3.8-RELEASE application stack behaves and 2.7.8
What happens is 2.3.8-RELEASE will work fine after changing port in "receiver" application but 2.7.8 will ONLY be able to communicate with "receiver" if below setting is set to "true":
spring.cloud.loadbalancer.health-check.refetch-instances=true
if it's not (and that is the default setting) the 2.7.8 will not be able to ever communicate with "receiver" unless "receiver" port will be reverted to original value and both applications restarted.
Here are some more significant elements of my configuration for Spring Boot 2.3.8-RELEASE:
Discovery service
Main class:
#SpringBootApplication
#EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
application.yml:
spring:
application:
name: eureka
eureka:
client:
registerWithEureka: false
fetchRegistry: false
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>eureka-old</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Eureka service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Caller service
Rest template configuration:
#Configuration
public class RestTemplateConfig {
#Bean
#LoadBalanced
#Qualifier("loadBalanced Rest Template")
RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
#Bean
#Qualifier("rest Template")
RestTemplate restTemplate() {
return new RestTemplate();
}
}
Controller:
#RestController
public class CallerController
{
private Rest Template restTemplate;
public CallerController (#Qualifier("loadBalancedRestTemplate") RestTemplate restTemplate)
{
this.restTemplate= restTemplate;
}
#GetMapping(value = "/call")
public String call()
{
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<String> (headers);
restTemplate.exchange("http://receiver/receive", HttpMethod. GET, entity, String.class);
System.out.println("Called.");
return "success";
}
}
pom.xml - only difference vs discovery service is load balancer is added:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
application.yml:
spring:
application:
name: caller
cloud:
loadbalancer:
ribbon:
enabled: false
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:8001/eureka/
Receiver application
Controller:
#RestController
public class ReceiverController
{
#GetMapping(value = "/receive")
public String receive()
{
System.out.println("Received.");
return "success";
}
}
application.yml:
spring:
application:
name: receiver
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:8001/eureka/
And here are some more significant elements of my configuration for Spring Boot 2.7.8: Discovery service
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka</name>
<description>Eureka service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Caller service
pom.xml:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.abednarski79</groupId>
<artifactId>caller</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>caller</name>
<description>Caller service</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Rest template configuration:
#Configuration
#LoadBalancerClient(value = "receiver", configuration = LoadBalancerConfig.class)
public class RestTemplateConfig {
#Bean
#LoadBalanced
#Qualifier("loadBalanced RestTemplate")
RestTemplate loadBalanced RestTemplate() {
return new RestTemplate();
}
#Bean
#Qualifier("rest Template")
Rest Template restTemplate() {
return new RestTemplate();
}
and load balancer configuration:
public class LoadBalancerConfig
{
#Bean
ServiceInstanceListSupplier serviceInstanceListSupplier(ConfigurableApplicationContext context, #Qualifier ("restTemplate") RestTemplate restTemplate) {
return ServiceInstanceListSupplier
.builder()
.withBlockingDiscoveryClient()
.withBlockingHealthChecks(restTemplate)
.build(context);
}
}
application.yml:
spring:
application:
name: caller
cloud:
loadbalancer:
health-check:
refetch-instances: false
eureka:
instance:
prefer-ip-address: true
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://localhost:9001/eureka/

camel 3.8 generates REST routes twice

I faced a problem with camel REST routes when I switched from camel version 3.5.0 to version 3.8.0.
In the version 3.8.0 all routes from the REST service are generated twice! So at start of the camel context the exception is thrown:
Failed to start route route7 because of Multiple consumers for the same endpoint is not allowed: jetty:http://0.0.0.0:6060/start?httpMethodRestrict=GET
In detail:
I have a simple RouteBuilder to generate REST routes:
#Component
public class RestInterface extends RouteBuilder {
#Override
public void configure() throws Exception {
restConfiguration()
.component("jetty")
.host(urlInfo.getHost())
.port(urlInfo.getPort())
.bindingMode(RestBindingMode.json)
.dataFormatProperty("prettyPrint", "true")
.clientRequestValidation(true);
rest("/")
.get("/start").outType(RepositoryPackageInfo.class).to("direct:start")
.get("/stop").outType(RepositoryPackageInfo.class).to("direct:stop");
// ...
}
}
When I start this code with camel 3.8.0 I get following console output:
...
jetty-9.4.31.v20200723; built: 2020-07-23T17:57:36.812Z; git: 450ba27947e13e66baa8cd1ce7e85a4461cacc1d; jvm 11.0.4+11
Started o.e.j.s.ServletContextHandler#5f65e0c0{/,null,AVAILABLE}
Started ServerConnector#27b7204{HTTP/1.1, (http/1.1)}{0.0.0.0:6060}
Started #4095ms
Error starting CamelContext (camel-1) due to exception thrown: Failed to start route route7 because of Multiple consumers for the same endpoint is not allowed: jetty:http://0.0.0.0:6060/start?httpMethodRestrict=GET
org.apache.camel.FailedToStartRouteException: Failed to start route route7 because of Multiple consumers for the same endpoint is not allowed: jetty:http://0.0.0.0:6060/start?httpMethodRestrict=GET
...
Apache Camel 3.8.0 (camel-1) shutting down (timeout:45s)
Stopped ServerConnector#27b7204{HTTP/1.1, (http/1.1)}{0.0.0.0:6060}
Stopped o.e.j.s.ServletContextHandler#5f65e0c0{/,null,UNAVAILABLE}
Routes shutdown summary (total:40 stopped:40) <-------------- total 40 routes!!!
...
Stopped route8 (rest://get:/:/stop)
Stopped route7 (rest://get:/:/start)
Stopped route2 (rest://get:/:/stop)
Stopped route1 (rest://get:/:/start) <-------------- the routes "stop" and "start" are doubled!!!
...
If I run the same code with camel 3.5.0, the application starts without exceptions, and camel has only 38 routes:
etty-9.4.31.v20200723; built: 2020-07-23T17:57:36.812Z; git: 450ba27947e13e66baa8cd1ce7e85a4461cacc1d; jvm 11.0.4+11
Started o.e.j.s.ServletContextHandler#6cbb6c41{/,null,AVAILABLE}
Started ServerConnector#42172065{HTTP/1.1, (http/1.1)}{0.0.0.0:6060}
Started #4034ms
Route: route1 started and consuming from: jetty:http://0.0.0.0:6060/start
Route: route2 started and consuming from: jetty:http://0.0.0.0:6060/stop
...
Total 38 routes, of which 38 are started <-------------- total 38routes!!!
...
Completed initialization in 16 ms
Thank you in advance. I hope somebody can help me with this issue.
For completeness, here is a part of my pom.xml
<!-- Camel -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-rest</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-zipfile</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-zipfile-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-bean-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-management</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring</artifactId>
<version>${camel.version}</version>
<scope>test</scope>
</dependency>
Check if configure method on your RestInterface RouteBuilder is getting called more than once. Multiple calls cause duplicate RouteDefinitions to be added to the RouteBuilder instance which can lead to this error.
One way to solve this is to use boolean value in your RouteBuilder to check if configure method has already been called. Then use this value to early out or to throw an exception.
boolean isConfigured = false;
#Override
public void configure() throws Exception {
if(isConfigured){
return;
}
// Configure routes
isConfigured = true;
}
Encountered similar problem with Camel 2.x running in Karaf + OSGi where modifying config file lead to same error.
Basically configuring CamelContext service caused it to restart while the RouteBuilder services it referenced kept their state leading to situation where their configure method got called the second time leading to same error.

Spring Cloud Config Server not registering as client to Spring Boot Admin

I have Spring Cloud config server and trying to register it to Spring Boot admin. In my pom.xml file I have
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-client</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.1.3.Release</version>
</dependency>
I have several other services registering, so I know I have all my URL and settings correct. But I am not seeing is the registering log in the config server logs.
Found the answer after running the config server in debug mode.
SpringBootAdminClientAutoConfiguration:
Did not match:
- Spring Boot Client is disabled, because 'spring.boot.admin.client.url' is empty. (SpringBootAdminClientEnabledCondition)
Matched:
- #ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
SpringBootAdminClientCloudFoundryAutoConfiguration:
Did not match:
- Spring Boot Client is disabled, because 'spring.boot.admin.client.url' is empty. (SpringBootAdminClientEnabledCondition)
Matched:
- #ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition)
Since the config server doesn't read from the config server git repo the client URL was not set.
Adding --spring.boot.admin.client.url=<url> to the startup fixed it.

Spring Cloud Connector and MongoDB Replica Set

I have developed a micro service in Spring boot and it is deployed in Cloud Foundry. MongoDB is a service created in PCF and it is a replica set type service. The mongodb service is bound to the micro service in PCF. I am using Spring cloud connector to automatically fetch the connection string for the mongodb service when deployed in cloud using the following code.
#Configuration
#Profile("cloud")
public class CloudFoundryDatabaseConfig extends AbstractCloudConfig{
#Bean
public Cloud cloud() {
return new CloudFactory().getCloud();
}
#Bean
public MongoDbFactory mongoFactory() {
return connectionFactory().mongoDbFactory();
}
}
This code is working perfectly fine when the mongoDB service is a standalone type. However if it is a replica set, i get a unknown host exception. Since the mongodb URI contains comma separated host names, it seems to be unresolved.
An example of MongoDB URI below.
"mongodb://username:password#101.23.65.41:28000,101.23.65.43:28000,101.23.65.45:28000/default?authSource=admin"
Error:
com.mongodb.MongoSocketException: mongod-node-0-310d0fd1.mongodb.internal: Name or service not known}, caused by {java.net.UnknownHostException
Pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-cloudfoundry-connector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-spring-service-connector</artifactId>
</dependency>
Please help.

Turbine Dashboard Is not Loading for Aggregation in Spring Cloud Microservice

I am trying to develop a spring cloud microservice using spring MVC and spring boot framework. And Eureka server , Zuul , Ribbon , hystrix and Turbine using for spring cloud. I already developed a microservice and implemented only hystrix dashboard. I am able to take hystrix dashboard. Now I am implementing more services. So I choosed turbine for aggregation of monitoring. But it not getting the dashboard.I implemented turbine in separate spring boot project.
My pom.xml containing,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>
And My main class containing,
#SpringBootApplication
#EnableHystrixDashboard
#EnableCircuitBreaker
#EnableTurbine
public class ZTurbineClientApplication {
public static void main(String[] args) {
SpringApplication.run(ZTurbineClientApplication.class, args);
}
}
And my Turbine project application.properties file containing,
server.port=8085
spring.application.name=espace-Turbine
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
turbine:
aggregator:
clusterConfig: APPCLUSTER
app-config: espaceService1,espaceService2
instanceUrlSuffix.APPCLUSTER: /hystrix.stream
And My previous first services's application.properties file like
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
spring.application.name=espaceService1
server.port=8080
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
And second service's application property file contains,
eureka.client.serviceUrl.defaultZone=http://localhost:8071/eureka/
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
spring.application.name=espaceService2
server.port=8081
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
these are my implementation details.
After I took URL "http://localhost:8085/hystrix.dashboard". And pasted "http://localhost:8085/turbine.stream?cluster=APPCLUSTER". But getting error like "Unable to connect to Command Metric Stream". Adding screenshots below.
You need to remove space from comma separated service names
turbine.aggregator.cluster-config=espace-Second_Microservice,espaceFirst_Microservice
You cannot aggregate streams from different cluster names, either use one cluster name in both espace-Second_Microservice and espace-First_Microservice or don't use cluster at all.
To define one cluster name use below config
eureka:
instance:
prefer-ip-address: true
leaseRenewalIntervalInSeconds: 3
leaseExpirationDurationInSeconds: 3
metadata-map:
cluster: APPCLUSTER
Use below mentioned config for turbine
turbine:
aggregator:
clusterConfig: APPCLUSTER
app-config: espace-Second_Microservice,espace-First_Microservice
instanceUrlSuffix.APPCLUSTER: /hystrix.stream
Use http://{turbine host}:{turbine Port}/turbine.stream?cluster=APPCLUSTER in Hystrix Dashboard