spring cloud之Eureka不能注銷docker部署的實例


1 起因

事件的起因是這樣的,我們在微服務改造的過程中,選擇將服務注冊到eureka中,開發的時候還好,使用場景是這樣的:

  • 在idea中啟動服務,成功注冊到eureka,關閉服務,eureka成功注銷該服務實例
  • java -jar方式啟動服務,成功注冊到eureka中,ctrl-c停止服務,eureka成功注銷該服務實例

有一天,在服務器上部署服務的時候,我們選擇了docker啟所有的服務,預料之外的事情發生了:

docker run 服務成功注冊到eureka,docker stop之后,eureka卻沒有將該服務實例注銷, 那就docker rm 將容器刪除,eureka中這個服務實例還是存在,這樣每docker run一下,eureka中就會多注冊一個實例,就多了好多僵屍實例。

eureka有問題?還是docker啟服務有問題?

我docker容器都干掉了,eureka中還存在這有點兒說不過去吧

2 手動下線

eureka不能自動給下線我就手動delete一下吧

DELETE http://{ip}:{port}/eureka/apps/{appName}/{inatanceId}

3 改實例ID

但是這樣就是你每重啟一下就得刪一下,很麻煩。發現容器啟的實例id都有個特點,containerId:服務名稱:服務端口號,物理機上啟的主機ip:服務名稱:服務端口號

那就eureka.instance.instance-id=${spring.application.name}:${server.port}定制一下實例id,這樣docker run的服務端口相同的話,實例id就會相同,比如都是rms:8080,這樣docker run多少次也不會有那么多僵屍實例了,后起的會把前邊兒啟的同id實例擠掉。

但是這也並沒有從實質上解決自動下線問題,到底是為什么呢?

4 優雅的停止容器

直到看到一個知識點兒你真的優雅的停止容器了嗎?不就是docker stop嗎,其實:

當你發出Docker stop命令時,Docker會很好地要求進程停止,如果進程在10秒內沒有關閉,它將強制終止進程。

docker stop命令首先嘗試通過向容器中的根進程(pid 1)發送sigterm信號來停止正在運行的容器。如果進程在超時期間沒有退出,則發送SIGKID信號。

雖然進程可以選擇忽略sigterm,但sigkill直接進入內核,內核將終止進程。這個過程根本看不到信號。

使用Docker Stop時,唯一可以控制的是Docker守護進程在發送sigkill之前等待的秒數:docker stop --time=30 foo

這才慌然大悟,啟容器,進入容器,殺進程:

這里如果kill -9 同樣不能正常下線,原因看圖,-9 也是發送的SIGKILL

忽然想到java -jar 方式起的服務可以正常注冊到eureka,ctrl-c可以正常停止進程使eureka成功注銷該實例,如果我nohup java -jar啟的服務,就不能ctrl-c了

只能kill掉進程了,貫用的kill -9 pid,發現這樣殺死的服務實例,確實eureka中也沒有下線。這樣就與docker stop服務實例不能正常注銷的原因一致了。

看來不能高興的太早,發現docker stop指定時間不好使:

docker stop --time=80 rms-consul

等呀等,真的等了80s強制退出,eureka並沒有注銷該實例,感覺這種方式不太好把握進程停止真正需要的時間,也可能這種方式就是無效。

到底應該如何優雅的停止容器?https://www.ctl.io/developers/blog/post/gracefully-stopping-docker-containers/

試了一圈還是這好使:

5 docker 不能正常停止服務是因為沒有正確的開始

說好的優雅停止容器,為啥還是不能優雅的解決問題呢?到目前為止其實就是正常的kill解決了問題,繼續找原因。找到dockerfile

ENTRYPOINT [ "sh", "-c", "/start.sh"]
$ cat start.sh  
java -jar /apps/rms.jar

這個問題是shell script接收SIGTERM信號,而沒有發送給通過shell腳本生成的java進程,因此spring boot無法正常退出。

解決辦法:

通過運行exec命令,它將代替shell進程把SIGTERM傳播到spring boot。

ENTRYPOINT [ "sh", "-c", "exec java -jar /apps/rms.jar"]

再次

docker build...
docker run...
docker stop rms

居然成功了,eureka也能成功注銷該容器實例了

再試一下上邊兒不生效的優雅停止容器方式也成功了,如:

docker kill -s SIGTERM rms

還是蠻優雅的嘛。

其實說來說去,就是只要能讓spring boot優雅退出,eureka就能讓該實例優雅注銷。

另外spring cloud consul也是如此。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM