Search code examples
spring-boot-admin

Spring Boot Admin can't differ between multiple service instances in Cloudfoundry


I got Spring Boot Admin running locally with Eureka Service Discovery (No SBA Dependeny in the Clients). Now i tried to deploy it in Cloudfoundry. According the Documentation, Version 2.0.1 should "support CloudFoundry out of the box".

My Problem is that when I scale a service up to multiple instances, they are all registered under the same hostname and port. Eureka shows me all Instances with their InstanceID that I configured like this:

eureka:
  instance:
    instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

But Spring Boot Admin only lists one instance with hostname:port as identifier. I think i have to configure something on the client so that it sends the instance ID per HTTP Header when registering. But i don't know how.


Solution

  • Apparently you have to set the ApplicationId and InstanceIndex that Cloudfoundry generates as Eureka ApplicationId and InstanceId at Startup/ContextRefresh of your Client.

    CloudFoundryApplicationInitializer.kt

    @Component
    @Profile("cloud")
    @EnableConfigurationProperties(CloudFoundryApplicationProperties::class)
    class CloudFoundryApplicationInitializer {
    
    private val log = LoggerFactory.getLogger(CloudFoundryApplicationInitializer::class.java)
    
    @Autowired
    private val applicationInfoManager: ApplicationInfoManager? = null
    
    @Autowired
    private val cloudFoundryApplicationProperties: CloudFoundryApplicationProperties? = null
    
    @EventListener
    fun onRefreshScopeRefreshed(event: RefreshScopeRefreshedEvent) {
        injectCfMetadata()
    }
    
    @PostConstruct
    fun onPostConstruct() {
        injectCfMetadata()
    }
    
    fun injectCfMetadata() {
    
        if(this.cloudFoundryApplicationProperties == null) {
            log.error("Cloudfoundry Properties not set")
            return
        }
    
        if(this.applicationInfoManager == null) {
            log.error("ApplicationInfoManager is null")
            return
        }
    
        val map = applicationInfoManager.info.metadata
        map.put("applicationId", this.cloudFoundryApplicationProperties.applicationId)
        map.put("instanceId", this.cloudFoundryApplicationProperties.instanceIndex)
    
        }
    }
    

    CloudFoundryApplicationProperties.kt

    @ConfigurationProperties("vcap.application")
    class CloudFoundryApplicationProperties {
        var applicationId: String? = null
        var instanceIndex: String? = null
        var uris: List<String> = ArrayList()
    }