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

相关文章

来自专栏jeremy的技术点滴

重搭docker集群

3355
来自专栏乐沙弥的世界

Oracle 基于用户管理恢复的处理

Oracle支持多种方式来管理数据文件的备份与恢复来保证数据库的可靠与完整。除了使用RMAN工具以及第三方备份与恢复工具之外,基于

432
来自专栏程序小工

windows7使用Sphinx+PHP+MySQL详细介绍

由于业务需要,需要做类似淘宝商城商品检索的功能,对于数据量很大的情况,MySQL 查询的效率损耗很大,需要使用专门的索引引擎进行搜索查询,实现功能,对于和 PH...

1481
来自专栏Seebug漏洞平台

MySQL远程代码执行/权限提升漏洞的分析与实践(CVE-2016-6662)

本文作者:安全小飞侠,原文链接:http://avfisher.win/archives/593 0x00 背景 2016年9月12日,国外安全研究人员Dawi...

3425
来自专栏Hadoop实操

使用命令行创建collection时Sentry给Solr赋权的问题

1753
来自专栏大魏分享(微信公众号:david-share)

厉害了!全CI/CD工具链的实现 | 基于OCP离线: Openshift3.9学习系列第五篇

干货巨献:Openshift3.9的网络管理大全.加长篇---Openshift3.9学习系列第二篇

1814
来自专栏Greenplum

Linux 常用命令(四)

# Default runlevel. The runlevels used are:

460
来自专栏黄希彤的专栏

用 yum 把服务器的 php 升级到 7

有个 discuz 论坛一直用的是 php5.3.3,php7 出来以后看到大片大片的好评,性能大幅度的提升,心里就种草了。正好 discuz 官方最近也从3....

6701
来自专栏杨建荣的学习笔记

Percona-toolkit的安装和配置(r8笔记第86天)

pt工具是非常实用有效的一个工具集,对于诊断常规问题还是非常有效的,相比于Oracle的工具,MySQL中没有那么多复杂的数据字典,在实现方式上相对更加轻巧,主...

3647
来自专栏Java帮帮-微信公众号-技术文章全总结

IntelliJ IDEA常用酷炫插件【面试+工作】

最近大部分开发IDE工具都切换到了,所以也花了点心思去找了相关的插件。这里整理的适合各种语言开发的通用插件,也排除掉IntelliJ IDEA自带的常用插件了(...

1123

扫码关注云+社区