加速和簡化構建Docker(基於Google jib)
其實jib剛釋出時就有關注,但是一直沒有用於生產,原因有二
- 基於 spotify/docker-maven-plugin (原作者已經停止維護docker-maven-plugin,建議使用 spotify/dockerfile-maven )的原有流程跑的好好的,沒動力換成jib
- Google jib 一直沒有釋出1.x ,擔心其不穩定
先簡單介紹一下: google jib 是Google於18年7月釋出的一個針對Java應用的構建映象的工具(支援 Maven 和 Gradle ) ,好處是能夠複用構建快取,能夠加快構建,減小傳輸體積(後文會詳細講解),並且讓Java工程師不需要理解Docker相關知識就可以簡單構建映象並且釋出到指定registry裡(不需要docker build , tag, push)
本文會依次講解三種java構建映象的方法,分別是 正統的Dockerfile , spotify/dockerfile-maven , Google jib
附贈 alibaba/arthas 的整合和使用方法
準備
- Maven3.5
- Git
- Jdk 1.8
- Docker
$ git clone https://github.com/anjia0532/jib-demo.git $ cd jib-demo $ mvn clean package -DskipTests $ mkdir docker $ cp ./target/*.jar ./docker 複製程式碼
Dockerfile
建立 ./docker/Dockerfile
,內容如下,需要注意此處為了方便理解,沒有進行改進(比如限制使用者,安裝必要軟體等)
FROM openjdk:8-jdk-alpine ADD *.jar /app.jar EXPOSE 8080 CMD java ${JAVA_OPTS} /app.jar 複製程式碼
詳情參見 官方文件Dockerfile reference
$ cd ./docker $ sudo docker build . -t jib-demo $ docker images --檢視本地images $ docker tag jib-demo anjia0532/jib-demo --不寫registry,則預設為docker hub registry,可以在build時,直接寫 $ docker push anjia0532/jib-demo -- 推送到registry 複製程式碼
小結
優點:不需要改造pom,靈活,配合CI工具,可以不侵入專案,運維可以針對性的進行安全加固,並且可以做到標準化
缺點:命令複雜,Java程式設計師需要學習Dockerfile命令,或者運維和java溝通不暢時,時區,軟體,甚至目錄等都可能有出問題
spotify/dockerfile-maven
需要注意,spotify/dockerfile-maven 是需要pom+Dockerfile一塊用的,而docker-maven-plugin是可選的
在專案根目錄建立Dockerfile,如下所示
FROM openjdk:8-jdk-alpine EXPOSE 8080 ARG JAR_FILE ADD target/${JAR_FILE} /usr/share/myservice/myservice.jar ENTRYPOINT ["/usr/bin/java", "-jar", "/usr/share/myservice/myservice.jar"] 複製程式碼
在pom裡增加dockerfile-maven-plugin到build標籤裡
<build> <plugins> ... <plugin> <groupId>com.spotify</groupId> <artifactId>dockerfile-maven-plugin</artifactId> <version>${dockerfile-maven-version}</version> <executions> <execution> <id>default</id> <goals> <goal>build</goal> <goal>push</goal> </goals> </execution> </executions> <configuration> <repository>anjia0532/dockerfile-maven-demo</repository> <tag>${project.version}</tag> <buildArgs> <JAR_FILE>${project.build.finalName}.jar</JAR_FILE> </buildArgs> </configuration> </plugin> ... <plugins> <build> 複製程式碼
執行如下命令進行構建
$ mvn package -DskipTests 複製程式碼
詳情參見 官方文件 spotify/dockerfile-maven
小結
優點:減少了docker build & tag & push 的操作,Java程式設計師能夠控制映象名
**缺點: **其實就是省了docker build & tag & push的操作,別的缺點一點沒落不說,還得改動pom,還得要求寫Dockerfile,tag只支援一個等等
Google jib
修改預設settings.xml,增加registry認證,參見 Authentication Methods
<settings> ... <servers> ... <server> <id>docker_hub</id> <username>MY_USERNAME</username> <password>{MY_SECRET}</password> </server> </servers> </settings> 複製程式碼
改動pom.xml 增加 jib外掛
<project> ... <build> <plugins> ... <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>1.0.0</version> <configuration> <from> <!-- 如果不需要arthas可以改為 registry.hub.docker.com/openjdk:8-jdk-alpine --> <image>registry.hub.docker.com/hengyunabc/arthas:latest</image> <credHelper>docker_hub</credHelper> </from> <to> <image>${project.artifactId}</image> <tags> <tag>latest</tag> <tag>${project.version}</tag> </tags> </to> <container> <mainClass>${start-class}</mainClass> <ports> <port>8080</port> <port>5701/udp</port> <port>8563</port> </ports> <entrypoint> <shell>sh</shell> <option>-c</option> <arg>java -cp /app/resources/:/app/classes/:/app/libs/* com.example.demo.DemoApplication</arg> </entrypoint> <appRoot>/app</appRoot> <useCurrentTimestamp>true</useCurrentTimestamp> </container> </configuration> </plugin> ... </plugins> </build> ... </project> 複製程式碼
執行 mvn clean compile jib:dockerBuild
構建docker映象
注意:
pom中用的是 registry.hub.docker.com/hengyunabc/arthas:latest
是 alibaba/arthas (阿里開源的一個Java診斷工具,便於線上除錯)封裝的docker映象,如果不需要可以改成 registry.hub.docker.com/openjdk:8-jdk-alpine
$ docker run -d --init -p8563:8563 --name demo demo:latest ## 下面是啟動arthas,如果使用的是openjdk映象請勿執行 $ docker exec -it demo /bin/sh $ jid=$(jps | grep App | awk '{print $1}') $ java -jar /opt/arthas/arthas-boot.jar --target-ip 0.0.0.0 ${jid} 複製程式碼
如果使用了arthas映象,可以訪問http://ip:8563 ,在頁面上填上宿主ip,點選Connect, 然後參考Arthas/命令列表瞭解Arthas命令用法

小結
優點:充分利用快取,加快構建,不強制依賴docker daemon,依賴簡單(在maven或gradle增加外掛即可)
缺點:不支援Docker RUN 命令(jib官方建議將run封裝到base映象),對entrypoint和cmd支援不太好(alpine預設不支援多工,跑java應用預設是pid 1 ,執行jmap等命令會報錯,參考 jmap not happy on alpine )
jib 快取策略
專案每次釋出實際上變更的程式碼量不大,尤其依賴的jar變動的可能性較小,如果按照前兩種方案構建映象,會導致每次都全量構建,會導致儲存和頻寬資源浪費。
Jib 如何讓開發變得更美好
Jib 利用了 Docker 映象的分層機制,將其與構建系統整合,並通過以下方式優化 Java 容器映象的構建:
- 簡單——Jib 使用 Java 開發,並作為 Maven 或 Gradle 的一部分執行。你不需要編寫 Dockerfile 或執行 Docker 守護程序,甚至無需建立包含所有依賴的大 JAR 包。因為 Jib 與 Java 構建過程緊密整合,所以它可以訪問到打包應用程式所需的所有資訊。在後續的容器構建期間,它將自動選擇 Java 構建過的任何變體。
- 快速——Jib 利用映象分層和登錄檔快取來實現快速、增量的構建。它讀取你的構建配置,將你的應用程式組織到不同的層(依賴項、資源、類)中,並只重新構建和推送發生變更的層。在專案進行快速迭代時,Jib 只講發生變更的層(而不是整個應用程式)推送到登錄檔來節省寶貴的構建時間。
- 可重現——Jib 支援根據 Maven 和 Gradle 的構建元資料進行宣告式的容器映象構建,因此,只要輸入保持不變,就可以通過配置重複建立相同的映象。
可以可以通過 mvn clean compile jib:buildTar
生成 target/jib-image.tar
然後用解壓縮工具解壓後進行分析,實際上jib會將lib中非快照部分放到一個層,將快照部分放到一個層,將原始碼編譯後放到一個層。。。
