line / armeria

Your go-to microservice framework for any situation, from the creator of Netty et al. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, Retrofit, Reactive Streams, Spring Boot and Dropwizard.
https://armeria.dev
Apache License 2.0
4.75k stars 902 forks source link

Cannot use acutator internal service of Armeria-Spring integration if `management.server.port` is enabled #4985

Open tomatophobia opened 1 year ago

tomatophobia commented 1 year ago

To use "actuator" internal service of Armeria, When I add "armeria-spring-boot3-actuator-starter" artifact and configure the both internal-services.port and management.server.port, java.net.BindException Address already in use occurred. FYI, If the management.server.port is not set or 1, no exception occurs. Below are my build.gradle and application.yml files.

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'

implementation "com.linecorp.armeria:armeria:1.23.1"
implementation "com.linecorp.armeria:armeria-spring-boot3-starter:1.23.1"
implementation "com.linecorp.armeria:armeria-spring-boot3-actuator-starter:1.23.1"
implementation "com.linecorp.armeria:armeria-tomcat10:1.23.1"
server.port: -1  # disable embedded tomcat service

armeria:
  ports:
    - port: 8000
      protocols:
        - HTTP
  internal-services:
    include: docs, metrics, health, actuator
    port: 8001

management:
  endpoints:
    web:
      exposure:
        include: env, health, metrics, prometheus
  server:
    port: 8002
tomatophobia commented 1 year ago

In my opinion, I believe the Tomcat service is the cause. When the management.server.port is not null or -1, Spring automatically starts the Actuator services on the port. Subsequently, Armeria automatically starts its internal services to the management.server.port when the armeria-spring-boot3-actuator-starter artifact is added and the management.server.port is not null. However, since the Tomcat service of Spring has already bound to that port, a java.net.BindException Address already in use error occurs.

This kind of issue can also occur with the server.port. When using the Tomcat service with Armeria, it is necessary to set the port as -1 to avoid port collision between Tomcat and Armeria. Therefore, the solution I propose is to set the management.server.port as -1 and introduce the armeria.internal-services.actuator-port to serve legacy Actuator services. Alternatively, if the use case of serving both internal services and Actuator services on management.server.port and armeria.internal-services.port is not crucial, it is also possible to forcefully set management.server.port to -1. I would like to hear the opinion on whether the proposed changes I suggested are reasonable

jrhee17 commented 1 year ago

Thanks for leaving an issue (I forgot about this πŸ˜… )

However, since the Tomcat service of Spring has already bound to that port, a java.net.BindException Address already in use error occurs.

This matches my analysis πŸ‘

the solution I propose is to set the management.server.port as -1 and introduce the armeria.internal-services.actuator-port to serve legacy Actuator services. Alternatively, if the use case of serving both internal services and Actuator services on management.server.port and armeria.internal-services.port is not crucial, it is also possible to forcefully set management.server.port to -1

For a bit of background, I think the original intention of the armeria's spring-boot[2|3]-actuator module was to service Spring's actuator services without Tomcat. For this reason, I think the behavior isn't very well defined when run with embedded tomcat like you mentioned.

If it is very important that Internal services and Actuator services are served on a different port, then I think introducing a separate armeria.internal-services.actuator-port could be useful like you mentioned πŸ‘

For most cases, I think usually it's enough to use internal-services.port for both actuator/internal services though. If you think dividing the ports is useful, I think it's reasonable to send over a PR though πŸ˜„

Is there a reason you would like to divide the ports? Did you have a use-case?

tomatophobia commented 1 year ago

Thank you for checking! I agree with your opinion. πŸ˜„ I think it's not a important feature from a use case perspective. I don't have such use case because I discovered this bug while investigating various aspects for writing a document on Spring integration. I think it is ok to close the issue. Thanks!