Docker下部署dubbo,消费者应用无法使用link参数的问题

在前一篇文章《Docker下dubbo开发,三部曲之一:极速体验》中,我们快速体验了部署在Docker环境下的dubbo服务,当时一共启动了四个容器,具体情况为:

容器

作用

镜像

功能

link连接

zk_server

一致性协调服务

zookeeper:3.3.6

官方镜像

dubbo_admin

注册中心

bolingcavalry/dubbo_admin_tomcat:0.0.1

定制镜像,用tomcat官方镜像加dubbo_admin.war生成

用别名zkhost连接zk_server

dubbo_provider

服务提供者

bolingcavalry/dubbo_provider_tomcat:0.0.1

定制镜像,用tomcat官方镜像加dubboserviceprovider.war文件生成

用别名zkhost连接zk_server

dubbo_consumer

服务消费者

bolingcavalry/online_deploy_tomcat:0.0.1

定制镜像,是个支持在线部署的tomcat

现状分析

在这个体验环境中,dubbo的服务提供者和消费者其实都是web应用,对应的是dubboserviceprovider.war和dubboserviceconsumer.war这两个文件,分别部署在docker容器的tomcat中。

把一个web应用在docker的tomcat容器中运行起来有两种方式: 1. 写Dockerfile文件做一个定制镜像,用tomcat官方镜像做基础镜像,在Dockerfile中将war包复制到tomcat的webapps目录下,dubbo_provider就是用这种方式; 2. 运行一个支持在线部署的tomcat容器,然后在线部署war包,具体细节请看《实战docker,编写Dockerfile定制tomcat镜像,实现web应用在线部署》,dubbo_consumer用的就是这种方式;

很明显,第一种方式用起来更简单,在docker-compose.yml中把镜像指定了就行,而第二种方式略为麻烦,要自己动手去部署war包;

问题出现

那么问题来了,既然第一种简单,为何dubbo_consumer不用这种方式呢,反而用更为麻烦的第二种?

回答这个问题之前,我们先看下提供服务的应用dubbo_provider,它用的是第一种方式,dubbo服务提供方要把自己注册到dubbo注册中心,所以必然要使用zookeeper服务,在docker-compose.yml中,dubbo_provider的配置如下:

dubbo_provider: 
    image: bolingcavalry/dubbo_provider_tomcat:0.0.1
    links: 
      - zk_server:zkhost
    depends_on:
          - "dubbo_admin"
    environment:
      TOMCAT_SERVER_ID: dubbo_provider_tomcat
    restart: always

dubbo_provider容器配置了link参数zk_server:zkhost,也就是用zkhost取代zookeeper的ip,这样服务提供者的代码中只要使用zkhost就能连接到zookeeper;

那么dubbo_consumer呢,如果也用link参数zk_server:zkhost,然后在代码中用zkhost取代zookeeper的ip,这样不就和dubbo_provider一样了么?

第一种方式的尝试

当初我的确是这么做的,用Dockerfile把dubbo_consumer的war包复制到tomcat镜像中,启动容器的时候用link参数zk_server:zkhost,代码中用zkhost替代zookeeper的ip,如下图:

在容器运行的时候抛出了以下错误:

May 16, 2017 12:27:35 PM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
May 16, 2017 12:27:35 PM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
May 16, 2017 12:27:38 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dubboServiceConsumeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bolingcavalry.service.CalculateService com.bolingcavalry.controller.DubboServiceConsumeController.calculateService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'calculateService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Failed to check the status of the service com.bolingcavalry.service.CalculateService. No provider available for the service com.bolingcavalry.service.CalculateService from the url zookeeper://zkhost:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo_service_consumer&dubbo=2.5.3&interface=com.bolingcavalry.service.CalculateService&methods=add&pid=1&side=consumer&timestamp=1494937657693 to the consumer 172.28.0.4 use dubbo version 2.5.3
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5118)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5634)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1571)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1561)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bolingcavalry.service.CalculateService com.bolingcavalry.controller.DubboServiceConsumeController.calculateService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'calculateService': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: Failed to check the status of the service com.bolingcavalry.service.CalculateService. No provider available for the service com.bolingcavalry.service.CalculateService from the url zookeeper://zkhost:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo_service_consumer&dubbo=2.5.3&interface=com.bolingcavalry.service.CalculateService&methods=add&pid=1&side=consumer&timestamp=1494937657693 to the consumer 172.28.0.4 use dubbo version 2.5.3
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    ... 22 more

注意这一行

No provider available for the service com.bolingcavalry.service.CalculateService from the url zookeeper://zkhost:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo_service_consumer&dubbo=2.5.3&interface=com.bolingcavalry.service.CalculateService&methods=add&pid=1&side=consumer&timestamp=1494937657693

zookeeper://zkhost:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo_service_consumer&dubbo=2.5.3&interface=com.bolingcavalry.service.CalculateService&methods=add&pid=1&side=consumer&timestamp=1494937657693是个url,用来查找服务的,这个url中有我们在xml中填入的zkhost。

问题分析

问题已经很清楚了,我们用zkhost替代ip原本是为了网络连接的时候,利用系统中host文件对zkhost的配置,来方便的连接到对应的ip,但是在dubbo的消费者服务中,dubbo运行时会把zkhost当作一个字符串来使用,拿这个字符串生成的url在dubbo注册中心是搜索不到的,因为服务在注册的时候注册中心记录的是ip;

基于以上原因,我才放弃了第一种部署方式,选择了先启动tomcat,再手工在线部署war包的方式(war包中zookeeper的ip已经写成真正的);

其实理论上第一种方式也是可以的,步骤如下: 1. 配置link参数zk_server:zkhost; 2. tomcat不再启动时自动执行; 3. 复制到镜像文件的web应用不是war包,而是从war包解压好的文件夹; 4. 制作一个shell,在容器启动的时候自动执行,shell的功能是从/etc/hosts文件中取得zkhost对应的ip,然后用sed命令将spring-extends.xml中的address=”zookeeper://zkhost:2181”替换成zkhost对应的ip; 5. 启动tomcat;

理论上这种方法也是可以的;

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SAP最佳业务实践

SAP最佳业务实践:MM–转包(138)-4发货过账

3.5 VL02N拣配确认(可选) 该活动拣配、包装并发运相关部件到供应商,此步骤只在拣配不需要 WM 调拨订单的情况下执行。 角色:仓库文员 后勤 -后勤...

3334
来自专栏javathings

Java 的 NIO 是如何工作的?

在这个数据爆炸的时代,有大量的数据在系统中流动,一个应用系统的瓶颈往往都是 IO 瓶颈。传统的 javaIO 模型是 BIO,也就是同步阻塞 IO,数据在写入 ...

1381
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–按计划协议的销售(231)-3发货

一、VL10E交货到期清单 在此活动中,可以处理交货到期清单,以便创建交货凭证。 角色仓库文员 后勤 → 后勤执行 → 外向处理→外向交货的发货→ 外向交货→ ...

5626
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–外贸出口处理(118)-4发货

一、VL10C创建交货 1. 在 销售订单项目 屏幕上,进行以下输入: 字段名称用户操作和值注释装运点/接收点<装运点> 交货创建日期(从)<输入交货创建日期>...

41410
来自专栏JavaEdge

Tomcat架构解析之3 Connector NIOAcceptorPollerWorkerNioSelectorPool

2904
来自专栏大数据架构

Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

2095
来自专栏女程序员的日常

STM8S——Analog/digital converter (ADC)

1、ADC1 and ADC2 are 10-bit successive approximation Anolog to Digital Converters...

3431
来自专栏计算机视觉战队

Caffe源码---Blob基本使用

看到这个的时候,估计你也在学习caffe,嘿嘿!Blob在内存中表示4维数组,维度从低到高为(width_,height_,channels_,num_)。Bl...

2644
来自专栏SAP最佳业务实践

SAP最佳业务实践:MM–交货与库存调拨(134)-5发货

4.5 VL10B采购订单的交货到期清单 该活动创建库存调拨订单的交货。 角色:仓库文员 后勤 -后勤执行-外向处理- 外向交货的发货 -外向交货 -创建-交货...

3705
来自专栏java 成神之路

NIO 之 Channel实现原理

47614

扫码关注云+社区

领取腾讯云代金券