encircle360 Blog

Using spring-boot microservices within kubernetes using native k8s service discovery and label filters

Since we’re migrating our whole netflix-oss cloud native and spring cloud infrastructure to kubernetes we would like to get rid of most netflix-oss dependencies because features like service discovery over eureka which is now provided natively by kubernetes mostly aren’t needed anymore since the netflix-oss stack was build when technologies like kubernetes weren’t born.

In most cases we are also getting rid of client-side-load-balancing over ribbon replacing it by kubernetes (virtual IPs) server-side tcp load-balancers (called services). It’s also possible to use client-side load balancing in kubernetes context furthermore but our real-world-use-cases have shown that in 95% of business and application logic the difference between both mechanisms are so small that they don’t really make any amount of difference having one hop between the calling service and called service. The benefit we get is that we have have dependency-less spring boot microservices and also services based on other technologies all using the same way of communication. You also should have less configuration affort since eureka isn’t needed anymore and the kubernetes default load balancing settings are working really well so rolling-upgrades with zero down-time are even more stable regardless how many pods or replicas of your service you have running. In 5% of the cases where it makes sense to use client-side-load-balancing you can still use it by plugging the corresponding dependencies in.

For classic spring-boot microservices

For classic spring-boot microservices this is easy. Just remove the @EnableServiceDiscovery annotation from your main class or configuration and remove eureka service discovery client dependency from your build file. Using Feign you now can use the hostname or FQDN defined by your service (we create them using helm) as url-parameter in the @FeignClient annotation.

@FeignClient(url = "http://your-k8s-service-name:port")

It should be possible to leave out the port and protocol and work with hostnames only. In this case you need port 80 in your kubernetes service definition forwarding to the real endpoint/pod port. This would lead to the following @FeignClient annotation.

@FeignClient(url = "your-k8s-service-name")

Using spring-boot-admin with the kubernetes service-discovery and label filter to monitor spring-boot-only services

At first you need the Discovery Client implementation that resolves service names to Kubernetes Services in your spring-boot-admin project. Just add it to your maven dependencies.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>

The same dependency for gradle (put it in your build.gradle file):

compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-kubernetes', version: '1.0.1.RELEASE'

If your spring boot microservices use a different management port (as we use for security reasons) you have to let the kubernetes-service-discovery client within spring-boot-admin know which port it should resolve or use. In this case you have to configure the primary port name for which the discovery client should decide if multiple ports are configured for a kubernetes service / endpoint.

spring:
  cloud:
    kubernetes:
      discovery:
        primaryPortName: management

Filtering the services spring-boot-admin should retrieve from kubernetes by labels

As we have a mixed stack and we have for example some nodejs services in our kubernetes namespace we wouldn’t like to let them occur in spring-boot-admin since they have no acuator and management endpoints. We can use filtering based on kubernetes service labels for that which isn’t really good documented at this time.

In this case we would only retrieve services from kubernetes that have the label “spring-boot=true“.

spring:
  cloud:
    kubernetes:
      discovery:
        serviceLabels:
          spring-boot: true

Retrieving kubernetes endpoints from multiple namespaces

As we have server relevant services for security reasons in their own namespace like “spring-server” we need at least the possibility to obtain endpoints from other namespaces or all namespaces. This doesn’t seem to be possible at this time without a workaround. You can find the workaround to obtain endpoints from all namespaces here.

 

Top
en_USEnglish