在Docker中运行Dubbo应用
更新歷史
- 2017.11.30 增加利用v3版本compose文件部署示例。
Dubbo概述
Dubbo是阿里開(kāi)源的一個(gè)分布式服務(wù)框架,在國(guó)內(nèi)粉絲很多。官網(wǎng)上的介紹是:
DUBBO是一個(gè)分布式服務(wù)框架,致力于提供高性能和透明化的RPC遠(yuǎn)程服務(wù)調(diào)用方案,是阿里巴巴SOA服務(wù)化治理方案的核心框架,每天為2,000+個(gè)服務(wù)提供3,000,000,000+次訪問(wèn)量支持,并被廣泛應(yīng)用于阿里巴巴集團(tuán)的各成員站點(diǎn)。
Dubbo的文檔很完整,網(wǎng)絡(luò)上資源也很多,這里就不再重復(fù)了。本文做這樣一個(gè)嘗試,將一個(gè)Dubbo應(yīng)用容器化,部署到阿里云的容器服務(wù)上。
極簡(jiǎn)Dubbo應(yīng)用結(jié)構(gòu)
在Dubbo世界里,服務(wù)調(diào)用方和服務(wù)提供方通過(guò)Dubbo的發(fā)現(xiàn)機(jī)制互相發(fā)現(xiàn)。一個(gè)最小的Dubbo應(yīng)用包含如下三個(gè)服務(wù):
- 服務(wù)提供者
- 服務(wù)調(diào)用方
- 發(fā)現(xiàn)機(jī)制(例如zookeeper)
zookeeper已經(jīng)有Docker鏡像了,下面我們就會(huì)用Spring Boot開(kāi)發(fā)服務(wù)提供方Service Producer和服務(wù)調(diào)用方Service Consumer。
定義服務(wù)接口
創(chuàng)建一個(gè)Maven模塊service-api,定義服務(wù)接口。
public interface Greetings {String say(String name); }這個(gè)接口很簡(jiǎn)單,就是問(wèn)好。
在pom.xml中引入對(duì)Dubbo的依賴:
<dependencies><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.5.3</version></dependency> </dependencies>我們用的是dubbo 2.5.3版本,讀者如果愿意嘗試更新的版本,可以自行升級(jí)。
服務(wù)提供方 Service Producer
創(chuàng)建一個(gè)Maven模塊service-producer,提供服務(wù)接口的實(shí)現(xiàn)。
public class GreetingsImpl implements Greetings {public String say(String name) {return "Greetings from " + name;} }為了能找到服務(wù)接口模塊,需要在pom.xml中定義對(duì)service-api的依賴。
<dependencies>...<dependency><groupId>com.example</groupId><artifactId>dubbo-service-api</artifactId><version>1.0-SNAPSHOT</version></dependency>Dubbo通過(guò)spring xml配置文件的方式聲明對(duì)zookeeper的訪問(wèn)。在resources目錄下創(chuàng)建services.xml,其中最重要的內(nèi)容是指定zookeeper的地址和端口,為了不把zookeeper的地址寫(xiě)死在配置文件中,我們采用環(huán)境變量來(lái)指明服務(wù)地址。這也是12 factor應(yīng)用的一個(gè)推薦實(shí)踐之一。
<dubbo:registry protocol="zookeeper" address="${ZOOKEEPER_SERVER}:2181" /><dubbo:protocol name="dubbo" port="20880" /><dubbo:service interface="com.example.service.Greetings" ref="greetingService"/><bean id="greetingService" class="com.example.service.producer.GreetingsImpl" />xml文件中的其他內(nèi)容包括指定本服務(wù)的偵聽(tīng)端口為20880,GreetingsImpl類實(shí)現(xiàn)的接口API類等。
下面要在pom.xml引入dubbo的項(xiàng)目依賴。
<dependencies>...<dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.5.3</version><exclusions><exclusion><artifactId>spring</artifactId><groupId>org.springframework</groupId></exclusion></exclusions></dependency><dependency><groupId>com.github.sgroschupf</groupId><artifactId>zkclient</artifactId><version>0.1</version></dependency>我們準(zhǔn)備用spring 4.x,所以把dubbo中自帶的老版本springframework剔除。
現(xiàn)在服務(wù)的實(shí)現(xiàn)類有了,我們需要一個(gè)主函數(shù)把實(shí)現(xiàn)類運(yùn)行起來(lái)。Springboot有一個(gè)很好的特性,就是把一個(gè)Java應(yīng)用的所有相關(guān)依賴打包成為一個(gè)超級(jí)JAR包,對(duì)于生成Docker鏡像來(lái)說(shuō)非常方便。
首先在pom.xml中引入springboot依賴。
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> ...創(chuàng)建一個(gè)Spring主應(yīng)用。由于Dubbo采用xml配置文件的方式,要通過(guò)@ImportResource聲明加載services.xml配置文件。
@SpringBootApplication @ImportResource({"classpath:services.xml"}) public class Application {public static void main(String[] args) throws Exception{SpringApplication.run(Application.class, args);} }Springboot Web應(yīng)用啟動(dòng)后會(huì)自動(dòng)偵聽(tīng)8080端口。不過(guò)我們?cè)谶@里沒(méi)有用到內(nèi)置的tomcat和8080端口。如果你不喜歡這個(gè)多余的tomcat,可以用spring-boot-starter替換本文中的spring-boot-starter-web項(xiàng)目,但要注意的是,沒(méi)有tomcat的代碼需要增加不退出應(yīng)用的邏輯。
服務(wù)調(diào)用方 Service Consumer
Service Consumer的結(jié)構(gòu)和Producer的結(jié)構(gòu)類似,也需要在pom.xml中引入對(duì)dubbo, service-api和springboot的依賴。在resouces目錄下創(chuàng)建services.xml,聲明zookeeper的地址和要訪問(wèn)的服務(wù)接口:
<dubbo:registry protocol="zookeeper" address="${ZOOKEEPER_SERVER}:2181" /> <dubbo:reference id="greetingService" interface="com.example.service.Greetings" />遠(yuǎn)程調(diào)用的服務(wù)bean名字為greetingService,在下面的代碼中要用到。
在Application主應(yīng)用中調(diào)用Service Producer。
Greetings greetingService = (Greetings)context.getBean("greetingService"); String result = greetingService.say("Dubbo Docker");為了能夠用HTTP訪問(wèn)Consumer應(yīng)用,我們用@RequestMapping將context root /映射到方法上。
@RequestMapping("/") public String greetings(){...Consumer啟動(dòng)偵聽(tīng)的端口在resources/application.properties文件中指定:
server.port=${SERVER_PORT:0}編譯并在本地運(yùn)行
在項(xiàng)目的根目錄下運(yùn)行Maven編譯:
mvn package從Docker鏡像中啟動(dòng)zookeeper,并把2181端口映射到本機(jī):
docker run -d -p 2181:2181 -p 2888:2888 -p 3888:3888 registry.aliyuncs.com/acs-sample/zookeeper:3.4.8在環(huán)境變量中指定zookeeper地址,啟動(dòng)Service Producer。
export ZOOKEEPER_SERVER=127.0.0.1 java -jar target/dubbo-service-producer-1.0-SNAPSHOT.jar啟動(dòng)Service Consumer時(shí)除了要指定zookeeper地址外,還要指定consumer自己偵聽(tīng)的地址,本示例中使用的是8899。
export ZOOKEEPER_SERVER=127.0.0.1 export SERVER_PORT=8899 java -jar target/dubbo-service-consumer-1.0-SNAPSHOT.jar訪問(wèn)一下cosumer的HTTP 8899端口,可以看到消息的輸出。說(shuō)明服務(wù)調(diào)用方從zookeeper中獲得了正確的producer的地址,并用dubbo遠(yuǎn)程調(diào)用協(xié)議成功調(diào)用了producer的GreetingService。
$curl http://localhost:8899/ Greetings from Dubbo Docker構(gòu)建Docker鏡像
為Producer和Consumer構(gòu)建Docker鏡像和正常的SpringBoot應(yīng)用一樣,Dockerfile內(nèi)容如下:
FROM openjdk:8-jre VOLUME /tmp COPY target/*.jar app.jar RUN sh -c 'touch /app.jar' CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]把這個(gè)文件分別放在Producer和Consumer的目錄下,執(zhí)行Docker的編譯命令即可打包生成容器鏡像。
在service-producer目錄下運(yùn)行:
mvn package docker build -t producer .生成service-consumer鏡像類似,這里就不重復(fù)了。
兩個(gè)鏡像生成后,可以用Docker Compose命令啟動(dòng)。對(duì)應(yīng)的docker-compose.yml內(nèi)容如下:
version: "2" services:zookeeper:image: 'registry.aliyuncs.com/acs-sample/zookeeper:3.4.8'hostname: zookeeperproducer:image: 'producer:latest'environment:- ZOOKEEPER_SERVER=zookeeperconsumer:image: 'consumer:latest'environment:- ZOOKEEPER_SERVER=zookeeper- SERVER_PORT=8899ports:- 8899:8899在這里把zookeeper容器的主機(jī)名hostname設(shè)置為zookeeper并通過(guò)環(huán)境變量傳給producer和consumer。運(yùn)行Docker Compose啟動(dòng)三個(gè)容器。
$docker-compose up -d Creating docker_consumer_1 Creating docker_zookeeper_1 Creating docker_producer_1容器啟動(dòng)成功后用同樣方式訪問(wèn)8899端口可以看到正確的輸出。
$curl http://localhost:8899/ Greetings from Dubbo Docker部署到阿里云容器上
好了,至此我們已經(jīng)成功地在本地Docker環(huán)境中運(yùn)行了Dubbo應(yīng)用,下面就要將這個(gè)應(yīng)用部署到阿里云容器服務(wù)上。
首先登陸阿里云Docker鏡像倉(cāng)庫(kù),地址在此https://cr.console.aliyun.com/,創(chuàng)建2個(gè)鏡像倉(cāng)庫(kù)。在本示例中命名為dubbo-springboot-producer和dubbo-springboot-consumer。
創(chuàng)建一個(gè)為阿里云部署的模版文件,docker-compose-acs.yml,內(nèi)容和docker-compose.yml類似。
version: "2" services:zookeeper:image: 'registry.aliyuncs.com/acs-sample/zookeeper:3.4.8'hostname: zookeeperproducer:image: 'registry.cn-hangzhou.aliyuncs.com/${rname}/dubbo-springboot-producer:latest'environment:- ZOOKEEPER_SERVER=zookeeperconsumer:image: 'registry.cn-hangzhou.aliyuncs.com/${rname}/dubbo-springboot-consumer:latest'environment:- ZOOKEEPER_SERVER=zookeeper- SERVER_PORT=8899labels:aliyun.routing.port_8899: http://ds-consumer這個(gè)部署文件和docker-compose.yml內(nèi)容不同之處在于,所有容器到主機(jī)端口映射都去掉了,為了能訪問(wèn)consumer,使用了aliyun.routing.port_8899為consumer指定一個(gè)子域名。集群部署后可用如下URL訪問(wèn)consumer服務(wù)。
http://ds-consumer.c67***8cd5.cn-shenzhen.alicontainer.com登陸阿里云容器服務(wù)控制臺(tái) https://cs.console.aliyun.com,利用部署模版創(chuàng)建一個(gè)新應(yīng)用,部署模版的內(nèi)容就是上面docker-compose-acs.yml內(nèi)容,提示rname時(shí)輸入你的容器倉(cāng)庫(kù)用戶名,很快應(yīng)用部署就會(huì)成功。
在控制臺(tái)中進(jìn)入consumer服務(wù)頁(yè)面,找到訪問(wèn)端點(diǎn):
點(diǎn)擊地址,可以在瀏覽器中看到輸出:
至此,我們成功地在云上運(yùn)行了Dubbo應(yīng)用。
本文中的compose模版部署為v2版本,如果大家想嘗試?yán)胿3版本部署,可以訪問(wèn)github
討論
在網(wǎng)上有討論容器化的Dubbo應(yīng)用發(fā)送的IP地址不對(duì),經(jīng)實(shí)測(cè)在Docker 1.12版本下沒(méi)有這個(gè)問(wèn)題,部署到阿里云容器服務(wù)上也正常。本文的示例代碼在github上,大家可以參考。
小節(jié)
本文通過(guò)Spring Boot構(gòu)建了一個(gè)最小的Dubbo應(yīng)用,容器化后成功部署到阿里云容器服務(wù)上。
總結(jié)
以上是生活随笔為你收集整理的在Docker中运行Dubbo应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 事务BEGIN TRANSACTION
- 下一篇: leetcode202(Floyd判圈算