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 条评论
登录 后参与评论

相关文章

来自专栏大数据架构

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

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

STM8S——Analog/digital converter (ADC)

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

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

SAP最佳业务实践:SD–销售订单处理:自库存销售(109)-3发货

VL10C交货处理 在此活动中,创建交货。 角色仓库文员 后勤 ®后勤执行®外向处理®外向交货的发货 ®外向交货®创建®交货凭证到期日的集中处理 ®销售订单项目...

3093
来自专栏蓝天

基于zookeeper的主备切换方法

继承CZookeeperHelper即可快速实现主备切换: https://github.com/eyjian/mooon/blob/master/mooo...

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

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

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

4416
来自专栏社区的朋友们

TAF 必修课(二):Reactor多线程模型

最近看了很多文章和分享,非常受益, 实习所做项目主要用到了TAF,有必要对之前的学习做个梳理和总结,网络线程模型及请求接收过程,必修亦为基础、通用,故取其名。

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

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

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

35710
来自专栏java 成神之路

NIO 之 Channel实现原理

44714
来自专栏清晨我上码

第六节 netty前传-NIO Selector

可以使用单个线程来处理多个channel来节省资源。对于操作系统而言,线程之间切换是昂贵的,并且每个线程也占用操作系统中的一些资源(存储器)。 因此,使用的线程...

782
来自专栏coolblog.xyz技术专栏

基于 Java NIO 实现简单的 HTTP 服务器

本文是上一篇文章实践篇,在上一篇文章中,我分析了选择器 Selector 的原理。本篇文章,我们来说说 Selector 的应用,如标题所示,这里我基于 Jav...

63312

扫码关注云+社区