1. 程式人生 > >Docker多步構建更小的Java映象

Docker多步構建更小的Java映象

譯者按: 最新版Docker將支援多步構建(Multi-stage build),這樣使用單個Dockerfile就可以定義多箇中間映象用於構建,測試以及釋出等多個步驟,並且有效減小最終映象的大小。

為了保證可讀性,本文采用意譯而非直譯。

  • Docker多步構建(Docker Multi-stage build)

這篇部落格介紹了為什麼需要Docker多步構建(Docker Multi-stage build),並且通過一個示例展示瞭如何構建更小的Java映象。

為什麼需要多步構建?

為Java應用構建Docker映象意味著編譯原始碼以及打包目的碼。開發者通常會使用Maven或者Gradle來構建JAR或WAR檔案。若使用Maven映象作為基礎映象來構建Java應用,則需要下載所有Maven依賴。下載的JAR包數目由pm.xml

決定,有可能會非常多。這樣的話,生成的Docker映象中將留下太多多餘的檔案。

下面為示例Dockerfile:

FROM maven:3.5-jdk-8
 
COPY src /usr/src/myapp/src
COPY pom.xml /usr/src/myapp
RUN mvn -f /usr/src/myapp/pom.xml clean package
 
ENV WILDFLY_VERSION 10.1.0.Final
ENV WILDFLY_HOME /usr
 
RUN cd $WILDFLY_HOME && curl http://download.jboss.org/wildfly/$WILDFLY_VERSION/wildfly-$WILDFLY_VERSION.tar.gz | tar zx && mv $WILDFLY_HOME/wildfly-$WILDFLY_VERSION $WILDFLY_HOME/wildfly
 
RUN cp /usr/src/myapp/target/people-1.0-SNAPSHOT.war $WILDFLY_HOME/wildfly/standalone/deployments/people.war
 
EXPOSE 8080
 
CMD ["/usr/wildfly/bin/standalone.sh", "-b", "0.0.0.0"]

maven:3.5-jdk-8 是基礎映象由Dockerfile可知:

  • 將原始碼拷貝到映象中
  • Maven用於構建應用
  • 下載並安裝WildFly
  • 將生成的.war檔案拷貝到WildFly的deployments目錄
  • 啟動WildFly

這個Dockefile存在這些問題:

  • 使用Maven作為基礎映象的話,還需要安裝和配置WildFly。
  • 構建應用時需要下載很多Maven依賴,它們會繼續留在映象中,但是執行應用時並不需要它們。這導致了映象過大。
  • 修改WildFly版本則需要修改Dockerfile,並重新構建映象。如果直接使用WildFly映象作為基礎映象,情況會簡單很多。
  • 打包應用之前,需要進行單元測試,那麼,測試的依賴也需要留在生成的映象中,這其實是沒必要的。

當然,也可以採用其他方式構建Docker映象。比如,可以將Dockerfile拆分為兩個。第一個Dockerfile以Maven映象為基礎映象,用於構建應用,並將構建好的.war檔案通過資料卷(volume)複製到共享的目錄;第二個Dockerfile以WildFly映象作為基礎映象,從資料卷將.war檔案拷貝出來就好了。這個方法也是有問題的,因為需要維護多個Dockerfile,並且通過資料卷拷貝檔案也不方便。

什麼是Docker多步構建?

多步構建(multi-stage build)允許在Dockerfile中使用多個FROM指令。兩個FROM指令之間的所有指令會生產一箇中間映象,最後一個FROM指令之後的指令將生成最終映象。中間映象中的檔案可以通過COPY --from=<image-number>指令拷貝,其中image-number為映象編號,0為第一個基礎映象。沒有被拷貝的檔案都不會存在於最終生成的映象,這樣可以減小映象大小。

FROM指令可以使用as <stage-name>來指定步驟名稱(stage name):

FROM maven:3.5-jdk-8 as BUILD

下面為示例Dockerfile:這樣的話,COPY指令的--from選項可以使用步驟名稱代替映象編號。

FROM maven:3.5-jdk-8 as BUILD
 
COPY src /usr/src/myapp/src
COPY pom.xml /usr/src/myapp
RUN mvn -f /usr/src/myapp/pom.xml clean package
 
FROM jboss/wildfly:10.1.0.Final
 
COPY --from=BUILD /usr/src/myapp/target/people-1.0-SNAPSHOT.war /opt/jboss/wildfly/standalone/deployments/people.war

一共有兩個FROM指令,因此為兩步構建。由Dockerfile可知:

  • maven:3.5-jdk-8 是第一步構建的基礎映象。這一步用於構建應用的WAR檔案。這一步的名稱為build
  • jboss/wildfly:10.1.0.Final 是第二步構建的基礎映象。第一步構建的WAR檔案通過COPY --from指令拷貝到WildFly的deloyments目錄。

Docker多步構建有什麼好處?

  • 僅需要一個Dockerfile來定義整個構建過程。這樣,不需要定義多個Dockerfile,也不需要使用資料捲來拷貝檔案。
  • 可以為最終映象選擇合適的基礎映象,來滿足生產環境的需求,這樣可以有效減小最終映象的大小。另外,構建步驟的多餘檔案都被丟棄了。
  • 使用官方的WildFly映象作為生產映象的基礎映象,而不是手動安裝和配置WildFly。這樣,WildFly升級時將非常方便。

注:Docker多步構建正在開發中,還沒有正式釋出。可以通過 curl -fsSL https://test.docker.com/ | sh命令安裝最新的測試版Docker試用多步構建。

使用第一個Dockerfile構建的映象為816MB,而使用多步構建的話,映象只有584MB。

docker-java-multistage $ docker images
REPOSITORY                          TAG                 IMAGE ID            CREATED             SIZE
people                              multistage          d36a4b82ad87        59 seconds ago      584MB
people                              singlestage         13dbcf8f54f6        5 minutes ago       816MB

檢視PR #31257,有更加詳細的討論。可知,使用多步構建可以有效減小映象大小。

關於Fundebug

Fundebug專注於JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了6億+錯誤事件,得到了Google、360、金山軟體等眾多知名使用者的認可。歡迎免費試用!

轉載時請註明作者以及本文地址: