上一篇有提及,depends_on無法確保他一定會等db都完整啟動了,才啟動app,所以會產生一些錯誤情境,這一篇我們就一起來解析他到底發生了哪些事?
可以看到執行過程,確實是先建立了network web_app_network,再建立db服務的mysql-3308 container,再建立app服務的my-spring-boot-app container。
但在執行過程中,很明顯看到其實mysql-3308 才 initialization 就開始執行 my-spring-boot-app了!
並沒有等候mysql-3308完全執行完畢。
app → 失敗,沒有連線到DB。
db → 成功,有啟動成功。
network 已創建出來
這邊不用擔心他會不會重複創建了network 以及 db container,只要判斷已經存在,就只會構建沒有的服務 my-spring-boot-app container
接著就能看到都能正常啟動成功囉!
查看web_app_network 也已經加入了 my-spring-boot-app container 到同一個網絡中
spring.datasource.url=jdbc:mysql://mysql-3308:3306/goal-life?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Taipei&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=pass
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
需要特別留意這邊URL的配置方式,是使用**<container的名稱>:<port號>
**
在docker-compose.yml檔案中配置了,app depends_on db的服務,所以這裡要使用db服務的container名稱作為連線依據,並且port號要使用MySQL預設的port號3306,才能正常連線成功。
spring.datasource.url=jdbc:mysql://db:3306/goal-life?...
spring.datasource.url=jdbc:mysql://mysql-3308:3308/goal-life?...
為了要驗證這件事,我嘗試了很多種排列組合都去執行看看,後來了解到…
因為把java web 丟到 docker中執行,對於docker中的環境來說,container之前是相互隔離的,為了能在不同的容器中做不同的事情,所以在執行中只會找相同網絡中的其他容器。
我們創建了一個network並把兩個容器中加到同一個網絡中,所以要使用depends_on服務的容器名稱作為連線的主機名稱,而對於容器內的連線port號是原先預設的3306,雖然我們映射到了本地的3308 port號,但那個是對於本地的執行連接來說,才能使用3308連接。
也就是說,我如果要從我本機使用MySQL workbench連接這個MySQL container的話,我要使用3308才能連接的到。