先说一下架构:标准Spring Cloud,注册中心使用Consul,Docker容器化部署。html
问题就出如今这个Consul和Docker的结合,现象就是在程序从新发布时,新的容器启动,在stop旧容器的时候,Consul注册中心的旧实例没有退出,并且咱们容器是随机IP地址,致使每次重启就会有无效的客户端,虽然不影响使用,可是在web端看到也是很烦的。java
在网上找了解决方案,这篇以为不错:www.cnblogs.com/sparkdev/p/…web
#!/usr/bin/env bash
set -x
pid=0
# 处理逻辑
term_handler() {
if [ $pid -ne 0 ]; then
kill -SIGTERM "$pid"
wait "$pid"
fi
exit 143; # 128 + 15 -- SIGTERM
}
# 监听
trap 'kill ${!}; term_handler' SIGTERM
# 启动Consul Client,本地调试,省略实际链接注册中心
nohup consul agent -data-dir /root/consul >/dev/null &
# 取得consul进程编号
pid="$!"
# 注意要保持后台运行,不然会阻塞
java -jar /app.jar --spring.profiles.active=dev &
# wait forever
while true
do
tail -f /dev/null & wait ${!}
done
复制代码
在程序从新发布项目,容器会把以前容器执行docker stop操做,这个操做只会给pid为1的进程(在咱们项目中就是docker_entrypoint.sh脚本执行的进程)发送SIGTERM信号,致使容器中Consul进程没有收到SIGTERM信号,被kill -9 强制杀掉,因此Consul没有给注册中心推送下线的信号,致使有注册中心有不少僵尸客户端。上面解决方式是在Consul进程启动后标记进程编号,并监听自身的SIGTERM信号,收到信号,在处理函数中给Consul进程编号传递SIGTERM,让Consul优雅的退出。spring