我参加的课程,网易云课堂《Java高级开发工程师》,它的容器化专题有一道作业题是:
把dubbo-admin服务部署到swarm集群上,并对容器进行动态扩容
我本以为这是一个简单的任务,不料部署时却出了岔子,Dubbo Admin服务死活不启动,最后调试到半夜3点才解决。以下是对整个过程的复盘。
环境
- VirtualBox
- Ubuntu 18.04.4
- Docker 19.03.12
我的虚拟机配置了两块网卡,一块是NAT模式,一块是Host-Only模式。通过修改netplan配置,我让Host-Only网卡的IP固定为192.168.1.1
.
使用的Dubbo Admin镜像是我上篇博文中构建的dubbo-admin:1.0
。
遭遇问题
启动一个Zookeeper容器:
docker run --name zookeeper -d -p 2181:2181 zookeeper:3.4
因为是作业而非生产环境部署,我打算只部署一个Zookeeper容器,无论有几个Dubbo Admin服务,让它们共用Zookeeper吧。
初始化Swarm集群:
docker swarm init --advertise-addr 192.168.1.1
这样就创建了一个单节点Swarm集群。集群中只有当前机器。当前机器是manager节点,但默认情况下manager节点也充当worker节点,可用于执行部署任务。
启动服务:
$ docker service create --replicas 1 --name dubbo-admin -p 7001:7001 dubbo-admin:1.0
image dubbo-admin:1.0 could not be accessed on a registry to record
its digest. Each node will access dubbo-admin:1.0 independently,
possibly leading to different nodes running different
versions of the image.
q9q6w0ex2g54on2fit4037ktw
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
查看:
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
q9q6w0ex2g54 dubbo-admin replicated 1/1 dubbo-admin:1.0 *:7001->7001/tcp
既然REPLICAS
一列显示1/1
,PORTS
一列也显示暴露了7001端口,那么服务应该已经部署好了,让我们用浏览器试一下:
这……什么情况😳
于是,我开始了艰辛的调试过程。
检查
先看看日志。
docker service logs dubbo-admin
docker logs zookeeper
观察到的现象:
- dubbo-admin的日志没有正常时多,打印到这几行就停下了
... dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:32.939 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 7001 (http) dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:33.001 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:33.001 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.31 dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:33.030 INFO 1 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64:/usr/lib/jvm/java-1.8-openjdk/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib] dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:33.201 INFO 1 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext dubbo-admin.1.25nb4xy6hc3x@u1 | 2020-08-01 16:44:33.201 INFO 1 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3681 ms
- zookeeper没有新日志,没有连接建立的信息出现
加上了-f
参数跟随查看。等待很久后,两个程序的日志仍然没有更新。
怀疑是Dubbo Admin卡死了。
查看JVM线程信息
由于日志中没有看到ERROR/WARN,所以决定使用jstack
深挖,看到底执行到了哪一步。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
297b10ac76e5 dubbo-admin:1.0 "java -Djava.securit…" 10 minutes ago Up 10 minutes 7001/tcp dubbo-admin.1.25nb4xy6hc3xp6c53aesknger
8bc166b7f703 zookeeper:3.4 "/docker-entrypoint.…" 30 minutes ago Up 30 minutes 2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp zookeeper
dubbo-admin对应的容器ID是297b10ac76e5
,记下它。
进入此容器,执行jstack
命令:
$ docker exec -it 297b10ac76e5 /bin/sh
/ # jps
1 jar
25 Jps
/ # jstack 1
1: Unable to get pid of LinuxThreads manager thread
可以看到,这里的jstack
命令运行出错了。出错的原因是我们企图访问PID为1的进程。
在正常的Linux系统下,PID为1的进程为init
,它对系统的正常运行有关键作用,不应被侵犯。jstack
为了防止用户误伤此进程,一旦检测到传入的PID为1就认定非法;然而在Docker容器中,PID为1的进程是主程序,它可能是普通的Java进程,访问它没有问题,但jstack
的开发者并没有考虑到这一点。
搜索解决方案。
有一些老外也发现了此问题,并提了issue, 似乎并未得到解决:Not able to run jmap, jstack, jcmd on alpine
但在这篇帖子末尾,有人推荐了一个小工具jattach, 可以完成类似的功能。