问题现象
当我们把微服务部署在docker 容器中, 注册在Eureka里的时候, 在Eureka的管理页面中见到的instance id是这样的:
instance_id:的值是 DockerId:spring.application.name: server.port
其实instance_id 的值是什么不是关键。
关键是当我们点解某个节点时, 它也是用dockerIid 当左 hostname去访问。这就出问题了‘
当我们查询日志时
07-21 14:47:24:274 DEBUG 1 --- [nio-8080-exec-3] c.i.order.mapper.OrderMapper.findById : <== Total: 1
url:http://DEMO-CLOUD-USER-SERVICE/user/2
07-21 14:47:24:724 INFO 1 --- [nio-8080-exec-3] c.netflix.config.ChainedDynamicProperty : Flipping property: DEMO-CLOUD-USER-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
07-21 14:47:24:790 INFO 1 --- [nio-8080-exec-3] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-DEMO-CLOUD-USER-SERVICE
07-21 14:47:24:791 INFO 1 --- [nio-8080-exec-3] c.netflix.loadbalancer.BaseLoadBalancer : Client: DEMO-CLOUD-USER-SERVICE instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=DEMO-CLOUD-USER-SERVICE,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
07-21 14:47:24:806 INFO 1 --- [nio-8080-exec-3] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
07-21 14:47:24:857 INFO 1 --- [nio-8080-exec-3] c.netflix.config.ChainedDynamicProperty : Flipping property: DEMO-CLOUD-USER-SERVICE.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
07-21 14:47:24:859 INFO 1 --- [nio-8080-exec-3] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client DEMO-CLOUD-USER-SERVICE initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=DEMO-CLOUD-USER-SERVICE,current list of Servers=[43ab279eaa63:8081, 3aab8fcfb8af:8081],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:106.12.129.49:8081; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 00:00:00 UTC 1970; First connection made: Thu Jan 01 00:00:00 UTC 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
, [Server:43.138.194.135:8081; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 00:00:00 UTC 1970; First connection made: Thu Jan 01 00:00:00 UTC 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0;stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@388efc08
07-21 14:47:24:913 ERROR 1 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://DEMO-CLOUD-USER-SERVICE/user/2": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)] with root cause
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_301]
见到 Eureka把 sevice demo_cloud_order_service 的 两个节点地址解释成 Servers=[43ab279eaa63:8081, 3aab8fcfb8af:8081],
导致访问失败。
解决步骤一
首先我们不能以hostname 注册Eureka, 必须用ip来注册。
在 微服务的application.yml 加上
eureka:
instance:
prefer-ip-address: true
这样注册后, instance_id的值还是不变的, 亦即系讲在Eureka管理页面, 你见到的仍然是
DockerId:spring.application.name: server.port
但是背后里面的地址已经改成ip地址了
但是上图的172.17.0.2 只微服务所在容器内的ip地址。。
这样这个地址还是不能被外部访问的。
解决步骤二
所以我们必须把 容器所在宿主机的ip 注册在Erueka.
对于这点, 我们可以添加配置
eureka.instance.ip-address=xxxxxxx
但是如果这个微服务会被部署到不同的server,或者多个server, 那么我们就不能把上面的配置项hardcode在 配置文件中.
个人建议把这个配置项用传参形式写 DockerFile上。
在DockerFile中最后的CMD 项我们加上这个启动配置项
# for CMD part, only allow ENV variables but not ARG variables
ENV env_jdk_path=$app_folder_path/jdk/bin/java
ENV env_jar_path=$app_folder_path/$app_folder_name/$app_package_name
ENV env_app_server_ip=$app_server_ip
#CMD tail -f /dev/null
CMD $env_jdk_path -jar $env_jar_path --eureka.instance.ip-address=$env_app_server_ip
然后在Jenkins里用Ip 传参给Docker File
//copy jdk path, ask dockerfile only could use the files in the directory
dir("${workspace_path}/${pom_folder}") {
sh "pwd"
sh "cp -a ${jdk_path4docker} ."
//build docker iamge
sh "docker build -t ${docker_repo}:${curr_tag_version} --build-arg app_server_ip=${app_server_ip} ."
}
解决步骤三
还有一样, 微服务会吧程序在容器内的端口注册上Eureka.
如果docker 的端口映射是另1个端口的话,还是会连接失败。
个人没找到 Eureka指定注册端口的配置。
所以个人建议只能保证微服务端口和docker容器映射的端口保持一样。
如果做足上面的三点, 我相信用docker微服务 注册Eureka的问题会被解决