2

We are currently using Spring Boot Admin for monitoring our microservices inside the OpenShift cluster.
Spring Boot Admin aplication get information about services from the Openshift's Service Discovery using spring-cloud-starter-kubernetes dependency.

Everything was fine until we deployed application with custom server.servlet.context-path.

For example, our microservice has server.servlet.context-path=/dictionary. However, Spring Boot Admin get the following information from the OpenShift's discovery:

{
    "registration": {
        "name": "dictionary-service",
        "managementUrl": "http://10.130.1.169:8080/actuator",
        "healthUrl": "http://10.130.1.169:8080/actuator/health",
        "serviceUrl": "http://10.130.1.169:8080/",
        "source": "discovery",
        "metadata": {
            "app": "dictionary-service",
            ...
        }
    }
}

So, Spring Boot Admin is expecting actuator working on "http://10.130.1.169:8080/actuator" but it's actually working on "http://10.130.1.169:8080/dictionary/actuator"

How can we customize managementUrl and healthUrl so our Spring Boot Admin server could use correct URL for monitoring this service?

3 Answers3

2

I got the same issue. But resolved with an other solution:

  1. I change the management port on my Spring Boot Application
management.server.port=8090
server.port=8080

Now the management end-points (/actuator, /actuator/health) aren't effected by "server.servlet.context-path".

  1. I opened the ports on my k8s deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: app
        image: ${docker_image}
        ports:
        - containerPort: 8080
        - containerPort: 8090
  1. I declared the ports with a name on my k8s service
kind: Service
apiVersion: v1
metadata:
  name: app-service
spec:
  selector:
    app: app
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
    name: api
  - protocol: TCP
    port: 8090
    targetPort: 8090
    name: management
  1. I said to Spring Boot Admin witch port name to use
spring.cloud.kubernetes.discovery.primary-port-name=management
Mathieu
  • 51
  • 1
  • 5
1

OK, so I finally solved it. Maybe it will be helpful for someone.

"registration" object from the question is generated in Spring Boot Admin itself. It's the reliability of the ServiceInstanceConverter interface. By default, DefaultServiceInstanceConverter implementation is used (you can read more about this here).

There are several metadata keys that can be used to modify your managementUrl and healthUrl (by default, "/actuator" and "/actuator/health" are used respectively).

First, I thought we can use management.context-path metadata key to append our server.servlet.context-path, but unfortunately, you can't use "/" character in metadata label value ("dictionary/actuator" is invalid), so it wasn't enough in my case.

Instead, we decided to extend DefaultServiceInstanceConverter and override convert and getManagementPath methods:

@Component
public class OpenShiftServiceInstanceConverter extends DefaultServiceInstanceConverter {

    private static final String MANAGEMENT_CONTEXT_PATH = "/actuator";
    private static final String MANAGEMENT_PREFIX = "management.prefix";

    @Override
    public Registration convert(ServiceInstance instance) {
        return Registration.create(instance.getServiceId(), getHealthUrl(instance).toString())
                .managementUrl(getManagementUrl(instance).toString()).serviceUrl(getServiceUrl(instance).toString())
                .metadata(getMetadata(instance)).build();
    }

    @Override
    protected String getManagementPath(ServiceInstance instance) {
        String managementPath = instance.getMetadata().get(MANAGEMENT_PREFIX);
        if (!isEmpty(managementPath)) {
            return managementPath + MANAGEMENT_CONTEXT_PATH;
        }
        return MANAGEMENT_CONTEXT_PATH;
    }
}

This way, we can just include server.servlet.context-path as metadata management.prefix key in service template:

kind: Template
apiVersion: v1
metadata:
  name: dictionary-service
annotations:
  description: Template for Dictionary Service 1.0.0
labels:
  app: dictionary-service
  management.prefix: dictionary
...

And now it is working like a charm.

1

It seems this is supported out-of-the-box if you add a "management.context-path" annotation to the Service metadata, e.g.:

apiVersion: v1
kind: Service
metadata:
  name: carts
  annotations:
    management.context-path: /carts/actuator

The Spring Boot Admin DefaultServiceInstanceConverter will automatically read from the Spring Cloud Discovery metadata and look for this to set up the proper management & health paths. For it to work you need to have the property spring.cloud.kubernetes.discovery.metadata.add-annotations set to true (which is the default anyways)

P.S.: I don't have an OpenShift cluster to test with but it worked for me locally with minikube and on an Amazon EKS cluster.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
jpt
  • 453
  • 7
  • 12