记一次问题处理-20190610(Consul)

1,313 阅读1分钟

🎯背景

先说一下架构:标准Spring Cloud,注册中心使用Consul,Docker容器化部署。

问题就出现在这个Consul和Docker的结合,现象就是在程序重新发布时,新的容器启动,在stop旧容器的时候,Consul注册中心的旧实例没有退出,而且我们容器是随机IP地址,导致每次重启就会有无效的客户端,虽然不影响使用,但是在web端看到也是很烦的。

🎯解决方案

在网上找了解决方案,这篇觉得不错:www.cnblogs.com/sparkdev/p/…

#!/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优雅的退出。