首頁 > 軟體

Java應用打包成Docker映象

2022-06-21 18:01:15

怎麼把Java應用打包成Docker映象?

對熟悉Docker的同學這應該是一個很簡單的問題,把專案打包成JAR包然後在Dockerfile裡用ADD命令把JAR檔案放到映象裡,啟動命令設定執行這個JAR檔案即可。

比如一個使用Maven構建的Spring應用就可以用下面這個Dockerfile構建映象。

FROM openjdk:8-jre
ADD target/*.jar /application.jar
ENTRYPOINT ["java", "-jar","/application.jar"]

上面這個Dockerfile很好理解,使用Maven構建的Java專案的目錄結構統一是

project
│   pom.xml
└───src // 原始檔目錄
│   │
│   └───main
│       │   
│       └───java
│       
└───target // class和jar檔案的目錄

用mvn clean package打包後會把JAR檔案生成在target目錄裡,通過java -jar命令即可執行編譯好的程式。

所以上面的Dockerfile裡就進行了把JAR從target目錄裡新增到Docker映象中以及將jar -jar /application.jar 設定成容器的啟動命令這兩步操作。

不過除了這種最原始的方法外我們還可以使用Maven的一些外掛,或者Docker的多階段打包功能來完成把Java應用打包成Docker映象的動作。

Maven外掛構建映象

Spotify公司的dockerfile-maven-plugin和Google公司出品的jib-maven-plugin是兩款比較有名的外掛,下面簡單介紹一下dockerfile-maven-plugin的設定和使用。

其實使用方法很簡單,我們在POM檔案裡引入這個plugin,並結合上面那個Dockerfile就能讓外掛幫助我們完成應用映象的打包。

<groupId>com.example</groupId>
    <artifactId>hello-spring</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>helloworld</name>
<plugin>
 <groupId>com.spotify</groupId>
 <artifactId>dockerfile-maven-plugin</artifactId>
 <version>1.4.10</version>
 <executions>
  <execution>
  <id>default</id>
      <goals>
        <goal>build</goal>
        <goal>push</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <repository>${docker.registry.url}/${image.prefix}/${artifactId}</repository>
    <tag>${project.version}</tag>
    <buildArgs>
      <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
    </buildArgs>
  </configuration>
</plugin>

外掛裡使用的docker.registry.url和image.prefix是我單獨為Docker的映象倉庫設定的屬性。

<properties>
 <java.version>1.8</java.version>
  <image.prefix>kevinyan001</image.prefix>
  <docker.registry.url></private.registry.url>
</properties>

這裡可以隨意設定成私有倉庫的遠端地址和映象字首,比如在阿里雲的映象服務上建立一個叫docker-demo的空間,上面的屬性就需要這樣設定:

<properties>
  <java.version>1.8</java.version>
  <image.prefix>docker-demo</image.prefix>
  <docker.registry.url>registry.cn-beijing.aliyuncs.com</docker.registry.url>
</properties>

在POM檔案裡設定好外掛後伴隨著我們打包應用執行mvc clean package操作時dockerfile-maven-plugin就會自動根據我們的設定打包好一個叫做kevinyan001/hello-spring:0.0.1-SNAPSHOT的Docker映象。

dockerfile-maven-plugin除了能幫助我們打包應用映象外還可以讓它幫助我們把映象push到遠端倉庫,不過我覺得用處不大,感興趣的同學可以去網上搜搜看這部分功能怎麼設定。

用Docker的多階段構建打包映象

上面介紹了使用Maven外掛幫助我們打包Java應用的映象,其實我們還可以把mvn clean package這一步也交給Docker來完成。當然把Java應用的原始碼放在Docker映象裡再編譯打包在釋出出去肯定是有問題的,我們知道在Dockerfile裡每個指令ADD、RUN這些都是在單獨的層上進行,指令越多會造成映象越大,而且包含Java專案的原始碼也是一種風險。

不過好在後來Docker支援了多階段構建,允許我們在一個Dockerfile裡定義多個構建階段,先拉起一個容器完成用於的構建,比如說我們可以在這個階段裡完成JAR的打包,然後第二個階段重新使用一個jre映象把上階段打包好的JAR檔案拷貝到新的映象裡。

這一點在Go語言比較有優勢,第一階段編譯好的二進位制執行檔案直接拷貝到一個最基礎的linux映象裡就能讓Go的應用在容器裡執行。關於Go應用的多階段打包,可以檢視我以前的文章線上Go專案的Docker映象應該怎麼構建? 進行了解。

使用下面的Dockerfile可以通過多階段構建完成Java應用的Docker映象打包。

# Dockerfile也可以不放在專案目錄下,通過 -f 指定Dockerfile的位置,比如在專案根下執行以下命令 
docker build -t <some tag> -f <dirPath/Dockerfile> .
FROM kevinyan001/aliyun-mvn:0.0.1 AS MAVEN_BUILD
COPY pom.xml /build/
COPY src /build/src
WORKDIR /build/
# mount anonymous host directory as .m2 storage for contianer 
VOLUME /root/.m2
RUN mvn clean package -Dmaven.test.skip=true --quiet
FROM openjdk:8-jre
COPY --from=MAVEN_BUILD /build/target/*.jar /app/application.jar
ENTRYPOINT ["java", "-jar", "/app/application.jar"]

上面我們用的這些Dockerfile也可以不用放在專案的根目錄裡,現在已經支援通過 -f 指定Dockerfile的位置,比如在專案根下執行以下命令完成映象的打包。

docker build -t kevinyan001/hello-spring:0.0.1 -f <dirPath/Dockerfile> .

上面第一個映象是我自己做的,因為Maven官方的映象的遠端倉庫慢的一批,只能自己包裝一下走阿里雲的映象源了。試了試速度也不快,主要是隨隨便便一個Spring專案依賴就太多了。大家如果這塊有什麼加快Docker 構建速度的方法也可以留言一起討論討論。

不可否認用多階段構建打出來的Go映象基本上是10M左右,但是Spring的應用隨隨便便就是上百兆,這個對容器的構建速度、網路傳輸成本是有影響的,那麼Spring應用的映象怎麼瘦身呢,這個就留到以後的文章進行探討了,更多關於Java打包成Docker映象的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com