在docker compose編排多個容器時,需要按實際情況控制各容器的啟動順序,本文是《docker compose下的java應用啟動順序兩部曲》的第一篇,文中會分析啟動順序的重要性,以及啟動順序有問題時會有什麼樣的影響,再給出臨時解決的和官方推薦的兩種解決方案,為下一篇的實戰做好鋪墊。 環境信 ...
在docker-compose編排多個容器時,需要按實際情況控制各容器的啟動順序,本文是《docker-compose下的java應用啟動順序兩部曲》的第一篇,文中會分析啟動順序的重要性,以及啟動順序有問題時會有什麼樣的影響,再給出臨時解決的和官方推薦的兩種解決方案,為下一篇的實戰做好鋪墊。
環境信息
本次實戰的環境如下:
- 操作系統:CentOS Linux release 7.7.1908
- docker:1.13.1
- docker-compose:1.24.1
spring cloud:Finchley.RELEASE
分散式環境中的依賴關係
在分散式環境中,各服務之間可能存在依賴關係,例如SpringCloud環境中的應用在啟動時都會先往註冊中心Eurka發起請求,如下圖(來自spring官方博客:https://spring.io/blog/2015/07/14/microservices-with-spring ):
從上圖可知,如果Eureka的服務不可用,就會影響業務服務的功能;
Docker環境中的依賴關係
- 上述服務如果用docker-compose編排在一起,也面依賴著問題:Eureka容器啟動完畢並且能提供http服務以後,業務服務的容器才能在Eureka註冊成功並取得服務列表,通常我們都使用depends_on參數來設定依賴關係;
- 以下是個docker-compose.yml文件,裡面有兩個容器:eureka和service,eureka是註冊中心,service是業務服務,service啟動後要去eureka註冊,為了確保啟動順序,service配置了depends_on參數:
version: '3'
services:
eureka:
image: bolingcavalry/eureka:0.0.1-SNAPSHOT
container_name: eureka
restart: unless-stopped
service:
image: bolingcavalry/service:0.0.1-SNAPSHOT
container_name: service
restart: unless-stopped
command: sh -c 'java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication'
depends_on:
- eureka
- 上述yml文件能解決依賴問題嗎?service服務啟動時能否成功在eureka註冊?來試試吧,在Linux電腦上創建docker-compose.yml文件,內容如上所示;
- 在docker-compose.yml所在目錄執行docker-compose up,docker服務會先去hub.docker.com下載鏡像,然後依次創建容器,控制台會同時列印eureka和service的日誌,如下圖所示,service註冊eureka失敗了,請註意圖中的文字分析:
- 為何會註冊失敗呢?繼續看後面的日誌,如下圖,service註冊失敗後eureka才初始化完成,所以前面的service註冊會失敗:
- 至此可以確定:depends_on參數可以確保eureka容器啟動後再啟動service容器,但我們真正想要的,是eureka容器啟動後,並且eureka服務初始化完畢進入可用狀態後,再啟動service容器,顯然depends_on參數達不到我們的要求;
- docker官方文檔也證實了這一點,如下圖紅框所示:
- 看來depends_on參數解決不了我們的問題,需要去尋找其他方法;
另外您可能會說:沒關係,service會自動重新註冊,但是在真實環境中,不是每個服務都有能力去自己解決依賴不可用的問題,例如spring-cloud-config服務如果起不來,依賴它的服務可能會立即停止;
有一種臨時方法(此方法V3版語法不再支持)
- 如果eureka容器配置了健康檢查,那麼service容器可以配置健康檢查依賴來控制啟動時機,具體的做法可以參考官方示例,如下所示,地址是:https://docs.docker.com/compose/compose-file/compose-file-v2/ :
version: "2.4"
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: redis
healthcheck:
test: "exit 0"
從上述編排內容可見:db容器有健康檢查,可以確定db容器的服務是否可用,web容器的depends_on參數內可以配置condition,這樣就做到了只有redis已經啟動並且db的健康檢查通過,才會啟動web容器;
- 上述配置看起來似乎是個不錯的方案,在我們這裡,只要給eureka配置要健康檢查,再讓service容器的depends_on參數內配置condition: service_healthy就可以了;
- 不幸的是:在docker-compose的第三版語法中,取消了condition參數!文檔地址是:https://docs.docker.com/compose/compose-file/ ,如下圖紅框所示:
- 因此,condition參數看似好用,但是從V3版開始的docker-compose.yml已經不再支持該參數,不能作為標準的解決方案;
官方推薦的方案
如下圖紅框所示,docker官方推薦使用wait-for-it.sh腳本來解決問題,地址:https://docs.docker.com/compose/startup-order/ :
至此,本篇已經分析了docker-compose下容器啟動順序的問題,下一篇文章,我們用SpringCloud應用來做實戰,將其做到在docker-compose下有序啟動;
參考文章
如果您對docker容器健康檢查有興趣,可以參考以下文章:
- 《極速體驗docker容器健康》;
-
歡迎關註公眾號:程式員欣宸