加速和簡化構建Docker(基於Google jib)

趙安家發表於2019-02-11

加速和簡化構建Docker(基於Google jib)

介紹

其實jib剛釋出時就有關注,但是一直沒有用於生產,原因有二

先簡單介紹一下: google jib 是Google於18年7月釋出的一個針對Java應用的構建映象的工具(支援MavenGradle) ,好處是能夠複用構建快取,能夠加快構建,減小傳輸體積(後文會詳細講解),並且讓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命令用法

snipaste20190208_201332.png

小結

優點: 充分利用快取,加快構建,不強制依賴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 容器映象的構建:

  1. 簡單——Jib 使用 Java 開發,並作為 Maven 或 Gradle 的一部分執行。你不需要編寫 Dockerfile 或執行 Docker 守護程式,甚至無需建立包含所有依賴的大 JAR 包。因為 Jib 與 Java 構建過程緊密整合,所以它可以訪問到打包應用程式所需的所有資訊。在後續的容器構建期間,它將自動選擇 Java 構建過的任何變體。
  2. 快速——Jib 利用映象分層和登錄檔快取來實現快速、增量的構建。它讀取你的構建配置,將你的應用程式組織到不同的層(依賴項、資源、類)中,並只重新構建和推送發生變更的層。在專案進行快速迭代時,Jib 只講發生變更的層(而不是整個應用程式)推送到登錄檔來節省寶貴的構建時間。
  3. 可重現——Jib 支援根據 Maven 和 Gradle 的構建後設資料進行宣告式的容器映象構建,因此,只要輸入保持不變,就可以通過配置重複建立相同的映象。

可以可以通過 mvn clean compile jib:buildTar 生成 target/jib-image.tar 然後用解壓縮工具解壓後進行分析,實際上jib會將lib中非快照部分放到一個層,將快照部分放到一個層,將原始碼編譯後放到一個層。。。

snipaste20190208_211839.png

參考資料

招聘小廣告

山東濟南的小夥伴歡迎投簡歷啊 加入我們 , 一起搞事情。

長期招聘,Java程式設計師,大資料工程師,運維工程師。

相關文章