【问题标题】:Spring cloud: Ribbon and HTTPSSpring Cloud:功能区和 HTTPS
【发布时间】:2015-08-17 19:53:38
【问题描述】:

我们希望使用 HTTPS 进行基于 Feign 和 Ribbon 的微服务通信。这些服务基于 Spring Boot,并且正确设置了 tomcat。这些实例使用 HTTPS URL 注册,并且在 Eureka 上启用了securePort。但是,当我们通过 Feign 调用另一个微服务时,底层的 Ribbon 无法识别协议并回退到 HTTP。我可以通过将协议添加到 FeignClient 注释来解决这个问题,如下所示:

    @FeignClient("https://users")

但似乎 Zuul 代理和 Hystrix/Turbine 也在内部使用 Ribbon 有相同的 HTTP 回退问题。有什么方法可以集中配置 Ribbon 以使用 HTTPS 作为默认值或使用注册的 eureka 实例的 securePort 设置?

Eureka 实例配置:

eureka.instance.hostname=localhost
eureka.instance.securePort = ${server.port}
eureka.instance.securePortEnabled = true  
eureka.instance.nonSecurePortEnabled = false 
eureka.instance.metadataMap.hostname = ${eureka.instance.hostname}
eureka.instance.metadataMap.securePort = ${server.port}
eureka.instance.homePageUrl = https://${eureka.instance.hostname}:${server.port}/
eureka.instance.statusPageUrl = https://${eureka.instance.hostname}:${server.port}/admin/info

通过这些设置,它在 Eureka 中看起来就像服务在 HTTPS 上运行一样。 Zuul 代理运行良好,但使用 HTTP URL 调用服务。您必须通过在密钥库中提供服务器证书来在 Spring Boots 嵌入式 Tomcat 中启用 SSL:

server.ssl.key-store=server.jks
server.ssl.key-store-password=<pw>
server.ssl.keyStoreType=jks
server.ssl.keyAlias=tomcat
server.ssl.key-password=<pw> 

Tomcat 不仅在 HTTPS 上运行并且 HTTP 端口被阻止,但我得到:localhost:8081 failed to respond,因为使用 HTTP URL 来调用服务。通过设置ribbon.IsSecure=true 可以正确生成用户服务url,但是功能区负载均衡器无法在Eureka 中查找用户服务:Load balancer does not have available server for client: users。我还尝试仅在 zuul 代理中设置 users.ribbon.IsSecure=true,但仍然出现相同的错误。

Caused by: com.netflix.client.ClientException: Load balancer does not have available server for client: user
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:468)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable.unsafeSubscribe(Observable.java:7304)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:112)
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:81)
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:59)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:77)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:41)
at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:30)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable.subscribe(Observable.java:7393)
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:441)
at rx.observables.BlockingObservable.single(BlockingObservable.java:340)
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:102)
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:81)
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.forward(RibbonCommand.java:129)
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:103)
at org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand.run(RibbonCommand.java:1)
at com.netflix.hystrix.HystrixCommand$1.call(HystrixCommand.java:298)

【问题讨论】:

  • 如果你使用eureka的securePort,那应该是eureka注册的端口。
  • 我确认 spencergibb 的评论:ZUUL 转发到侦听 443 的服务没有任何问题(确保您在客户端中启用了“eureka.instance.securePortEnabled=true”的安全端口)但是,我想知道您是否不应该总是在 @FeignClient 注释中使用“http”而不是“https”,无论您的实例正在侦听的实际端口是什么。
  • 我猜该服务已正确注册到 eureka。我们正在使用以下属性:eureka.instance.securePort = ${server.port} eureka.instance.securePortEnabled = true eureka.instance.nonSecurePortEnabled = false 但仍然得到com.netflix.zuul.exception.ZuulException: Forwarding error Caused by: com.sun.jersey.api.client.ClientHandlerException: org.apache.http.NoHttpResponseException: &lt;host&gt;:8081 failed to respond
  • 对不起,我正忙于其他事情,但今天我可以进一步调试一下。我认为神奇在于LoadBalancerContext.deriveSchemeAndPortFromPartialUri()。当我设置ribbon.IsSecure=true 时,服务的 URL 计算在reconstructURIWithServer() 中是正确的,例如https://&lt;host&gt;:8081/users/1。但是 Eureka 中的服务查找在 LoadBalancerContext.getServerFromLoadBalancer() 中失败,因为 URL 是 https://&lt;host&gt;:443 而不是 https://&lt;host&gt;:8761。下周继续调试……
  • 到目前为止没有运气。我们在 443 上配置了 Eureka 监听,但现在获取 Load balancer does not have available server for client: users,所以看起来 LoadBalancerContext.getServerFromLoadBalancer() 无法查找用户服务实例。我们希望在 HTTPS 上运行所有微服务,其中一些微服务在一台主机上运行,​​并根据端口进行区分。所以我们不能选择使用默认端口。任何想法如何设置?

标签: spring spring-boot spring-cloud


【解决方案1】:

添加 isSecure:true 后,也可能存在握手不成功的可能性,遇到过这种情况,我通过添加如下所示的 Truststore 解决了这个问题

-Djavax.net.ssl.trustStore="//.JKS 文件的位置" 和 -Djavax.net.ssl.keyStorePassword="有效密码"。

这个帮助我解决了 HTTPS 握手问题

【讨论】:

    【解决方案2】:

    我们现在通过设置解决了zuul代理问题

    ribbon.IsSecure=true
    eureka.instance.secureVirtualHostName=${spring.application.name}
    

    以便所有服务也在com.netflix.discovery.shared.Applications 的安全虚拟主机池中。这有助于发现过程在 eureka 中找到实例。

    不过,Hystrix 的仪表盘还是有类似的问题

    【讨论】:

    • 这两个属性应该添加到哪里?我将这两个属性添加到启用了 HTTPS 并注册到 Eureka 的 Spring Boot 应用程序中。当 Zuul 尝试将请求路由到它时,看起来 Zuul 仍在尝试为其使用 HTTP url。原因:org.apache.http.ProtocolException:服务器未能在 org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:151) ~[httpclient-4.3.6.罐子:4.3.6]
    • 我也将这两个属性添加到我的 Zuul Route 应用程序的 yaml 文件中,但仍然面临同样的问题。 org.apache.http.ProtocolException: 服务器未能响应有效的 HTTP 响应
    【解决方案3】:

    我在尝试配置 Zuul 代理以使用 Ribbon 连接到在 https 上运行的微服务时遇到同样的问题:RibbonRoutingFilter 正在查看 requestURI 并在执行 run 方法时创建 RestClient。我将 Eureka 配置为在 http 上运行。是注册在Eureka上的底层https微服务,Ribbon无法访问。

    http 与设置的简单 zuul 路由完美配合。

    【讨论】:

    • 是的,通过指定功能区 isSecure 解决了这个问题,并实现了一个自定义 socketfactory 来接受你想要的证书。 `实例:securePort:${server.port}secureVirtualHostName:${spring.application.name}元数据映射:instanceId:“${spring.application.name}:${spring.application.instance_id:${server.port}} " preferIpAddress: true securePortEnabled: true nonSecurePortEnabled: false ribbon: IsSecure: true CustomSSLSocketFactoryClassName: YourCustomSocketFactory `
    猜你喜欢
    • 2019-04-28
    • 2020-10-24
    • 2022-06-29
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 2019-06-19
    相关资源
    最近更新 更多