在篇(4)中,我们已经完成了prodService的开发,在该工程目录下,运行mvn clean package
命令即可完成打包,生成prodService-1.0-SNAPSHOT.jar,并且所有依赖包已经生成到lib目录。
接下来介绍如何在docker中运行该jar。
- 先将jar和lib复制到统一目录,以下选取目录/Users/joey/DockerImages/Producer为例
- 创建start_provider_docker.sh,传入dubbo端口号,运行jar
在该脚本中,我们将*.jar重命名为app.jar,从参数获取dubbo端口号,如未指定则使用默认端口号30881,然后运行app.jar
#!/bin/bash
cd $(dirname $0)
SERVER_NAME="Prod-Service-Provider"
JAR_FILE="app.jar"
SERVER_PORT="30881"
LOGS_DIR="logs"
DUBBO_OPTS=""
if [ -n "$1" ]; then
SERVER_PORT=$1
fi
DUBBO_OPTS="-Ddubbo.protocol.port=$SERVER_PORT"
if [ ! -d $LOGS_DIR ]; then
mkdir $LOGS_DIR
fi
STDOUT_FILE=$LOGS_DIR/stdout.$SERVER_PORT.log
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_MEM_OPTS=""
BITS=$(java -version 2>&1 | grep -i 64-bit)
if [ -n "$BITS" ]; then
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1g -Xmn256m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
JAVA_MEM_OPTS=" -server -Xms256m -Xmx1g -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi
rm app.jar
cp *.jar app.jar
echo -e "Starting $SERVER_NAME ...\c"
java $JAVA_OPTS $JAVA_MEM_OPTS $DUBBO_OPTS -jar $JAR_FILE
运行start_provider_docker.sh 30811验证脚本是否正确
3.创建run_provider.sh,封装启动docker容器并运行provider
将jar所在目录挂载到/home目录,在启动ibmjava容器后,运行start_provider_docker.sh,传入dubbo端口号
#!/bin/bash
docker run --name comm-provider-$1 --net=host -v /Users/joey/DockerImages/Producer:/home ibmjava /home/start_provider_docker.sh $1
接下来,运行run_provider.sh 31811,我们就可以指定该provider以容器方式在31811端口运行了。
joeys-MacBook-Pro:Producer joey$ pwd
/Users/joey/DockerImages/Producer
joeys-MacBook-Pro:Producer joey$ ls
Dockerfile lib prodService-1.0-SNAPSHOT.jar start_provider_docker.sh
app.jar logs run_provider.sh
joeys-MacBook-Pro:Producer joey$ run_provider.sh 31811
189b37b1854bd32b460f43f3f6552c71ad32ca67ba6857563212da9f76d52d21
joeys-MacBook-Pro:Producer joey$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
189b37b1854b ibmjava "/home/start_provi..." 6 hours ago Up 2 minutes comm-provider-31811
joeys-MacBook-Pro:Producer joey$
如果未使用-d模式运行docker,可以直接从日志发现provider无法连接到zookeeper服务注册中心。这是因为在docker容器内,如果需要访问安装在宿主机上的数据库或中间件,是不能直接使用127.0.0.1这个ip的,这个ip在容器中指向容器自己。
解决方案:
获取当前宿主机ip, 并在运行docker时添加--add-host参数,将当前宿主机ip记为zkserver添加到容器的hostname中。
修改run_provider.sh为如下:
#!/bin/bash
HOSTIP=$(ifconfig en0 | grep inet | grep -v inet6 | cut -d ' ' -f2)
docker run --add-host=zkserver:$HOSTIP --name comm-provider-$1 --net=host -v /Users/joey/DockerImages/Producer:/home ibmjava /home/start_provider_docker.sh $1
同时,修改prodService中的prodService.provider.xml,将dubbo注册服务ip改为使用hostname zkserver。
<!-- dubbo:registry address="zookeeper://127.0.0.1:2181" check="false" subscribe="false" register="true"/ -->
<dubbo:registry address="zookeeper://zkserver:2181" check="false" subscribe="false" register="true"/>
4.启动prodWebApplication,验证provider是否注册成功
这里prodWebApplication暂时还是直接从idea中启动,后续讲述如何将web应用通过容器来启动。
web应用启动失败,且我们发现抛出了异常:
com.alibaba.dubbo.remoting.RemotingException: client(url: dubbo://218.205.57.154:31811/com.boli.service.intfc.prod.IProdSvc?anyhost=true&application=prodSvcConsumer&check=false&codec=dubbo&default.timeout=5000&dubbo=2.5.3&heartbeat=60000&interface=com.boli.service.intfc.prod.IProdSvc&methods=sayHello,getProdList&pid=7434&revision=1.0.0&side=consumer×tamp=1490081635751&version=1.0.0) failed to connect to server /218.205.57.154:31811 client-side timeout 3000ms (elapsed: 3066ms) from netty client 192.168.0.109 using dubbo version 2.5.3
at com.alibaba.dubbo.remoting.transport.netty.NettyClient.doConnect(NettyClient.java:127) [dubbo-2.5.3.jar:2.5.3]
at com.alibaba.dubbo.remoting.transport.AbstractClient.connect(AbstractClient.java:280) ~[dubbo-2.5.3.jar:2.5.3]
这里奇怪的是,虽然我们使用了--net=host的方式来启动容器,但是在容器向zookeeper注册的时候却是使用的218.205.57.154这个ip,而不是宿主机的ip。导致consumer在查找provider的时候,无法识别该容器的内部ip。
解决方法:
指定容器的hostname指向到宿主机。具体修改run_provider.sh如下:
#docker run -d --add-host=zkserver:$HOSTIP --name comm-provider-$1 --net="host" -v /Users/joey/DockerImages/Producer:/home ibmjava /home/start_provider_docker.sh $1
#assign docker container's hostname to the host machine's ip address as below
docker run -d --add-host=zkserver:$HOSTIP --add-host=svcprovider:$HOSTIP --hostname svcprovider --name comm-provider-$1 --net="host" -v /Users/joey/DockerImages/Producer:/home ibmjava /home/start_provider_docker.sh $1
移除之前的容器实例并重新启动,然后重启web应用。
后续讲述zookeeper也通过容器启动时,如何实现zookeeper/provider/consumer容器之间的交互。