Docker多步構建更小的Java鏡像

譯者按: 最新版Docker將支持多步構建(Multi-stage build),這樣使用單個Dockerfile就能夠定義多箇中間鏡像用於構建,測試以及發佈等多個步驟,而且有效減少最終鏡像的大小。java

原文: Creating Smaller Java Image using Docker Multi-stage Buildgit

譯者: Fundebuggithub

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

Github倉庫: arun-gupta/docker-java-multistage小程序

DockerCon 2017中與Java開發者直接相關的內容有:微信小程序

這篇博客介紹了爲何須要Docker多步構建(Docker Multi-stage build),而且經過一個示例展現瞭如何構建更小的Java鏡像。bash

爲何須要多步構建?

爲Java應用構建Docker鏡像意味着編譯源代碼以及打包目標代碼。開發者一般會使用Maven或者Gradle來構建JAR或WAR文件。若使用Maven鏡像做爲基礎鏡像來構建Java應用,則須要下載全部Maven依賴。下載的JAR包數目由pm.xml決定,有可能會很是多。這樣的話,生成的Docker鏡像中將留下太多多餘的文件。微信

下面爲示例Dockerfile:oracle

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"]

由Dockerfile可知:app

  • maven:3.5-jdk-8 是基礎鏡像
  • 將源代碼拷貝到鏡像中
  • 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

這樣的話,COPY指令的--from選項可使用步驟名稱代替鏡像編號。

下面爲示例Dockerfile:

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

由Dockerfile可知:

  • 一共有兩個FROM指令,所以爲兩步構建。
  • 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累計處理了7億+錯誤事件,獲得了Google、360、金山軟件、百姓網等衆多知名用戶的承認。歡迎免費試用!

 

 

 

 

相關文章
相關標籤/搜索