您好,登錄后才能下訂單哦!
這篇文章主要講解了“Jib構建鏡像的問題分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Jib構建鏡像的問題分析”吧!
通過Jib插件將SpringBoot工程制作成Docker鏡像成功,但是運行鏡像的時候報錯(Could not find or load main class ${start-class})
在Maven工程中可以使用Jib插件將當前Java工程構建成Docker鏡像
操作系統:macOS Mojave 10.14.6 (18G103)
JDK:10.14.6 (18G103)
Docker:10.14.6 (18G103)
SpringBoot:2.1.8.RELEASE
Jib插件版本:1.6.1
為了重現問題,我將出現問題的SpringBoot工程上傳到GitHub,地址和鏈接信息如下表所示:
名稱 | 鏈接 | 備注 |
---|---|---|
項目主頁 | https://github.com/zq2599/blog_demos | 該項目在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該項目源碼的倉庫地址,https協議 |
git倉庫地址(ssh) | git@github.com:zq2599/blog_demos.git | 該項目源碼的倉庫地址,ssh協議 |
</br>
這個git項目中有多個文件夾,本章的應用在jib-error-demo文件夾下,如下圖紅框所示:
在pom.xml文件所在目錄執行命令<font color="blue">mvn clean compile -U</font>,鏡像可以構建成功,但是控制臺輸出了警告信息,如下圖:
嘗試用此鏡像創建容器,行命令<font color="blue">docker run --name=test bolingcavalry/hellojib:0.0.1-SNAPSHOT</font>,報錯如下:
CN0014005932:~ zhaoqin$ docker run --name=test bolingcavalry/hellojib:0.0.1-SNAPSHOT Error: Could not find or load main class ${start-class}
<font color="blue">docker ps -a</font>查看容器信息如下,只能看到狀態是"退出",別的沒啥了:
CN0014005932:~ zhaoqin$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d618f6588821 bolingcavalry/hellojib:0.0.1-SNAPSHOT "java -Xms4g -Xmx4g …" 4 minutes ago Exited (1) 4 minutes ago test
不甘心,用命令<font color="blue">docker ps -a --no-trunc</font>查看未截斷的容器信息:
CN0014005932:~ zhaoqin$ docker ps -a --no-trunc CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d618f6588821f00d3bd0b67a85ff92988b90dfff710370c9d340d5c544c550af bolingcavalry/hellojib:0.0.1-SNAPSHOT "java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* ${start-class}" 7 minutes ago Exited (1) 7 minutes ago test
這次有新發現,容器啟動時執行命令是<font color="blue">java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* ${start-class}</font>,怪哉!這個<font color="red">${start-class}</font>是什么?我們來看一個正常鏡像的啟動命令:
java -Xms4g -Xmx4g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.jiberrordemo.JibErrorDemoApplication
如上所示,<font color="blue">com.bolingcavalry.jiberrordemo.JibErrorDemoApplication</font>是main方法所在類,此命令可以正常運行JibErrorDemoApplication類的main方法; 6. 小結問題:容器啟動時執行java命令,把<font color="blue">${start-class}</font>作為參數傳給java,導致java無法處理此參數,所以進程報錯,導致容器退出;
此問題的原因很簡單:<font color="blue">java工程中帶有main方法的類不止一個</font>,去查看jib-error-demo工程的代碼,發現Utils.java中果然有個main方法:
public class Utils { public static String time(){ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()).toString(); } public static void main(String[] args){ System.out.println(time()); } }
將上述main方法刪除掉,再構建鏡像并運行容器,證實問題已經解決。
如果不想動Utils類的代碼(也許jar包中某個類帶有main方法),請打開pom.xml文件,在jib插件的配置中增加<font color="blue">mainClass</font>節點,節點內容是指定的class類,如下圖紅框所示: 經過上面的設置,問題也可以解決。
接下來,如果您有興趣了解更深層次的原因,咱們一起來深度探險吧。
這個問題在Jib的官方GitHub上是有記錄的,先看第一條,地址是:https://github.com/GoogleContainerTools/jib/issues/1601 ,如下圖紅框所示,同樣的問題,最后issue的發起人自己關閉了這個issue,因為他發現這自己的項目中有兩個帶有main方法的類:
再來看看這個issue, https://github.com/GoogleContainerTools/jib/issues/170 ,Jib的作者Q Chen推測是Spring將<font color="blue">${start-class}</font>這個字符串設置為Main-Class屬性的值(個人感覺,這里說的Spring應該是spring boot的mave插件吧),于是Jib插件在使用Main-Class的值得時候,拿到的就是<font color="blue">${start-class}</font>這個字符串了:
170這個issue的后續情節很有意思,Jib作者Q Chen對這個問題也很糾結,如果Java工程中發現了多個帶有main方法的類,Jib究竟該如何處理呢?Q Chen最后決定輸出警告,如下圖:
一起來看看這段代碼吧,也就是上圖中#288,地址是:https://github.com/GoogleContainerTools/jib/pull/228/files/c8757e1f9ea47edd78df18142de7836a68f22034 ,如果mainClass不像一個class類的名稱,就輸出警告,這個邏輯在Gradle和Maven插件中都寫入了:
最后一個問題:上面代碼中的mainClass從哪來的?打開上圖的源碼,地址是:https://github.com/GoogleContainerTools/jib/blob/c8757e1f9ea47edd78df18142de7836a68f22034/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildImageMojo.java ,如下圖紅框,從方法名可以推測,該值來自構建SpringBoot工程的maven插件,所以前面Q Chen提到main-class變量的值是Spring修改的,應該是來自這段代碼: 此時的您,如果依然意猶未盡,咱們再來鞏固一下SpringBoot的start-class
熟悉SpringBoot的同學其實對<font color="blue">${start-class}</font>并不陌生,當工程中多個類中都有<font color="blue">main</font>方法時,使用該參數來指定SpringBoot的啟動類;
先看SpringBoot官方文檔熟悉一下<font color="blue">start-class</font>,地址是:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/ ,下圖內容比較關鍵:我們設置的啟動類被指定到<font color="blue">Start-Class</font>屬性中,而<font color="blue">Main-Class</font>屬性變成了<font color="blue">org.springframework.boot.loader.JarLauncher</font>,這才是SpringBoot真正的啟動類:
如下圖,這是個補充說明,<font color="blue">Main-Class</font>屬性的值被轉移到<font color="blue">Start-Class</font>屬性這個動作,是maven插件在構建jar的時候做的:
所以start-class的值是來自main-class,再看main-class的值從哪里來,如下圖紅框所示,maven插件會去查找帶有<font color="blue">public static void main(String[] args)</font>的類:
感謝各位的閱讀,以上就是“Jib構建鏡像的問題分析”的內容了,經過本文的學習后,相信大家對Jib構建鏡像的問題分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。