譯者按: 最新版Docker將支持多步構建(Multi-stage build),這樣使用單個Dockerfile就可以定義多個中間鏡像用於構建,測試以及發布等多個步驟,並且有效減小最終鏡像的大小。
原文: Creating Smaller Java Image using Docker Multi-stage Build
譯者: Fundebug
為了保證可讀性,本文采用意譯而非直譯。
Github倉庫: arun-gupta/docker-java-multistage
DockerCon 2017中與Java開發者直接相關的內容有:
- Docker多步構建(Docker Multi-stage build)
- Oracle JRE in Docker Store
這篇博客介紹了為什么需要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"]
|
由Dockerfile可知:
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、金山軟件、百姓網等眾多知名用戶的認可。歡迎免費試用!
版權聲明:
轉載時請注明作者Fundebug以及本文地址: https://blog.fundebug.com/2017/05/02/about-docker-sock/