使用Dockerfile將原始碼構建成容器鏡像,進行鏡像分發、部署。相比於Golang或Python專案,Java專案因企業一般會選擇自建依賴倉庫(如Maven)導致容器化構建難度高,因不熟悉Dockerfile緩衝機制導致構建速度較慢。本文從典型使用者情境(雲上自建GitLab代碼倉庫、自建Maven倉庫)出發,介紹如何利用Dockerfile構建Java專案,如何提速構建過程以及如何利用ACR-EE構建服務來進行自動化鏡像構建。
前提條件
已建立GitLab代碼倉庫。
已建立Maven倉庫。
已建立ACR-EE企業版,更多內容,請參見建立企業版執行個體。
專案介紹
本文使用具有依賴的兩個Java專案進行示範。分別有以下兩個專案:
Provider:提供服務,供調用。
Core模組:提供公用介面。
Service模組:服務實現模組。
Consumer:調用Provider服務。
Service模組:需要依賴Provide專案裡的Core模組。參考代碼如下:
. ├── consumer │ ├── Dockerfile │ ├── consumer.iml │ ├── pom.xml │ └── service │ ├── pom.xml │ ├── src │ └── target └── provider ├── Dockerfile ├── core │ ├── pom.xml │ ├── src │ └── target ├── pom.xml ├── provider.iml └── service ├── pom.xml ├── src └── target
構建產物:
基於Provider工程構建出生產者應用鏡像。
基於Consumer工程構建出消費者應用鏡像。
步驟一:確定公用依賴包已上傳
專案引用的公用依賴包需要提前上傳到自建Maven倉庫。以這裡的Provider為例,您可以在Provider目錄下執行以下上傳命令:
mvn clean install org.apache.maven.plugins:maven-deploy-plugin:2.8:deploy -DskipTests
步驟二:製作專屬Maven基礎鏡像
為了在容器化構建環境內能訪問到自建Maven倉庫,需要把Maven倉庫配置放到基礎鏡像內。這裡建議基於官方Maven鏡像來打造您的企業專屬公用Maven基礎鏡像,應用專案直接引用該基礎鏡像即可訪問Maven倉庫。
將以下檔案儲存成Dockerfile並和Maven倉庫的《settings.xml》檔案放到同一目錄。
FROM maven:3.8-openjdk-8 #指定與專案匹配的Maven鏡像,該樣本環境為3.8版本的Maven。 ADD settings.xml /root/.m2/ #將自建Maven倉庫配置放到對應位置。
執行以下命令構建並推送到遠程鏡像倉庫。
ls Dockerfile settings.xml docker build -t demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 -f Dockerfile . Sending build context to Docker daemon 7.68kB Step 1/2 : FROM maven:3.8-openjdk-8 ---> a3f42bfde036 Step 2/2 : ADD settings.xml /root/.m2/ ---> db0d5a5192e3 Successfully built db0d5a5192e3 Successfully tagged demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 docker push demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8
步驟三:構建Consumer應用鏡像(Provider專案略過)
執行以下命令。(建議將構建過程中需要的基礎鏡像全部推送到阿里雲鏡像倉庫。)
FROM demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 AS builder
# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./service service/
# package jar
RUN mvn clean package
# Second stage: minimal runtime environment
From demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/openjdk:8-jre-alpine
# copy jar from the first stage
COPY --from=builder service/target/service-1.0-SNAPSHOT.jar service-1.0-SNAPSHOT.jar
EXPOSE 8080
CMD ["java", "-jar", "service-1.0-SNAPSHOT.jar"]
步驟四:最佳化構建速度
在步驟三:構建Consumer應用鏡像(Provider專案略過)中,您已經能構建出鏡像,但是當您修改代碼、重複構建時會發現每次都會重複拉取JAR包,而無法利用到JAR包緩衝,構建速度比較緩慢。這是因為Dockerfile有自己的緩衝生效機制,當修改原始碼後,ADD指令內的檔案內容hash後出現了值變化導致RUN指令需要重新構建,沒辦法利用到先前的構建結果緩衝。更多內容,請參見關於緩衝和Dockerfile最佳實務。
我們最佳化構建速度的思路是將Maven依賴能緩衝並重複利用:
首先將專案的《pom.xml》檔案拷貝進容器,下載依賴。只要專案不改動《pom.xml》檔案,後續構建都能利用到緩衝。
拷貝專案的源碼並編譯。
一個改進的Dockerfile如下所示,專案首次構建耗時43s,後續如果僅僅是改動原始碼構建時間可以縮短到7s。
FROM demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/maven-base:3.8-openjdk-8 AS builder
# To resolve dependencies in a safe way (no re-download when the source code changes)
ADD ./pom.xml pom.xml
ADD ./service/pom.xml service/pom.xml
RUN mvn install
ADD ./service service/
# package jar
RUN mvn clean package
# Second stage: minimal runtime environment
From demo-registry-vpc.cn-beijing.cr.aliyuncs.com/demo/openjdk:8-jre-alpine
# copy jar from the first stage
COPY --from=builder service/target/service-1.0-SNAPSHOT.jar service-1.0-SNAPSHOT.jar
EXPOSE 8080
CMD ["java", "-jar", "service-1.0-SNAPSHOT.jar"]
步驟五:基於ACR-EE的自動化構建流程
ACR-EE提供了企業級構建服務能力,推薦企業客戶使用,更多內容,請參見使用企業版執行個體構建鏡像。
以下將為您介紹幾個在使用過程中會用到的最佳實務。
使用VPC內網構建模式
針對雲上自建GitLab,建議使用VPC內網安全構建模式來構建鏡像, 避免向公網暴露服務。更多內容,請參見使用VPC安全構建模式構建容器鏡像。
使用鏡像版本不可變功能
推薦倉庫開啟版本不可變功能,以防止線上版本被覆蓋。
建立基於Commit ID的構建規則
每次構建產生兩個鏡像版本,一個版本使用代碼Commit ID來表示,方便鏡像版本和代碼版本對應起來;另一個版本使用latest表示最新版本。
提交代碼並觸發構建。下圖是提交兩次代碼後自動觸發的兩次構建過程,每次都產生了兩個鏡像,並且因為快取命中加速原因,第二次構建更快。