先說一下架構:標準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