概念
Google Jib 容器化建構工具
Jib
是
google
開源的
Java容器化工具
,可以
直接建構 Java 應用
的
Docker 和 OCI 鏡像的類庫
,以
Maven 和 Gradle 插件
形式提供。
通過 Jib
,Java 開發者可以
使用他們熟悉的 Java 工具來建構容器
。Jib 是一個
快速而簡單
的容器鏡像建構工具,它負責處理
将應用程式打包到容器鏡像中所需的所有步驟
。它
不需要你編寫 Dockerfile 或安裝 Docker
,而且可以
直接內建到 Maven 和 Gradle中
——
隻需要将插件添加到建構中,就可以立即将 Java 應用程式容器化
。
Docker 建構流程
Jib 建構流程
簡單
——Jib使用Java開發,并作為
Maven或Gradle的一部分運作
。你
不需要編寫Dockerfile或運作Docker守護程序,甚至無需建立包含所有依賴的大JAR包
。因為
Jib與Java建構過程緊密內建
,是以它
可以通路到打包應用程式所需的所有資訊
。在後續的容器建構期間,它将自動選擇Java建構過的任何變體。
快速
——Jib利用
鏡像分層
和
系統資料庫緩存
來
實作快速、增量的建構
。它
讀取你的建構配置
,将你的
應用程式組織到不同的層
(依賴項、資源、類)中,并隻
重新建構和推送發生變更的層
。在項目進行快速疊代時,
Jib隻将發生變更的層(而不是整個應用程式)推送到系統資料庫來節省寶貴的建構時間
。
可重制
——Jib支援
根據Maven和Gradle的建構中繼資料進行聲明式的容器鏡像建構
,是以,隻要輸入保持不變,就可以
通過配置重複建立相同的鏡像
。
簡化
快速 — 快速部署您的更改。Jib 将你的應用程式分成多個層,從類中分離依賴項。你不必等待 Docker 重建整個 Java 應用程式 —— 隻需部署更改的層即可
可重制 — 使用相同内容重建容器鏡像
Daemonless — 減少 CLI 依賴性。從 Maven 或 Gradle 中建構 Docker 鏡像,然後推送到你選擇的任何系統資料庫,無需編寫 Dockerfiles 并調用 docker build/push
下圖為某
微服務開啟 Jib 建構後在 Jenkins 中的建構過程
,可以看出
建構速度的提升主要在 package 和 push 階段
。
原理
假設我們有一個項目,其組織結構如下:
parentPro
|-- moduleA
|-- moduleB
|-- rest [rest 子產品為 spring boot 啟動入口,并依賴 moduleA、moduleB]
對于
SpringBoot 項目
,Maven 的
預設建構工具
是
Spring-boot-maven-plugin
,建構出
産物為
Fat Jar
。
Fat jar
中包含有
rest 子產品中的 classes
,及
rest 所依賴的 moduleA、moduleB
及其他
第三方 jar 庫
。最終,通過
Jenkins
的
Dockerfile
檔案将 Fat jar 基于 JDK 基礎鏡像層建構,産生一個新的應用鏡像。
每次應用建構新版本鏡像時,因為 Maven 建構産出物是 Fat jar,當 rest、moduleA、moduleB 子產品中任意一處發生變化時,都會産出一個新的 Fat jar。建構鏡像時都要将整個 Fat jar 重新寫入到鏡像層,并将整個鏡像層推送到鏡像倉庫中,大大降低了鏡像建構和推送的性能,并導緻同一個應用鏡像的多個 Tag 占用大量的存儲空間。
Jib 在
編譯 Java 應用時
,會
将 Java 項目
内的
資源及所依賴的資源
,
基于變化頻率不同分成多個部分
,并
将每個部分都單獨作為一個鏡像層
存在,這樣
其中一部分資源發生變化
時,
隻需要重新建構該部分所屬鏡像層即可
。
以第二節的應用為例,rest 應用鏡像将被分為以下鏡像層:
Classes
: rest 子產品中的
class
資訊,這部分資訊
變化頻率最高
,處于
最上層鏡像層
;
Resources
: rest 子產品中的
配置檔案
,這部分資訊
變化頻率較低
,處于
第二層鏡像層
;
Project Dependencies
: rest 子產品的
項目依賴資訊
,在目前示例中為 moduleA、moduleB,這部分内容比依賴第三方 Jar 庫更容易變化,是以也單獨做為一個鏡像層存在;
Snapshot Dependencies
:rest 子產品所依賴的 SnapShot Jar 庫;
All other Dependencies
: rest 子產品所依賴的其他類型 Jar 庫;
Each extra directory
:其他所依賴額外資源目錄;
基于
Jib 插件建構出的鏡像,與使用以下 Dockerfile 所建構出的鏡像相同
:
使用
關鍵幾步
配置 parent 的 pom
<properties>
<!-- 要想本地可以上傳到阿裡雲,請使用公網位址 registry.cn-shenzhen.aliyuncs.com -->
<docker.repostory>registry-vpc.cn-shenzhen.aliyuncs.com</docker.repostory>
<docker.repostory.namespace>syp-app</docker.repostory.namespace>
<docker.project.version>1.0</docker.project.version>
</properties>
<build>
<pluginManagement>
<plugins>
<!-- spring-boot-maven-plugin -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<!-- 拉取所需的基礎鏡像 - 即建構本鏡像所基于的根鏡像 -->
<from>
<image>${docker.repostory}/syp-common/openjdk:8-jdk-alpine</image>
<auth>
<username>在阿裡雲上的賬号</username>
<password>阿裡雲注冊的密碼</password>
</auth>
</from>
<!-- 最後生成的鏡像配置 -->
<!-- 表示本鏡像建構完成後,要釋出到哪裡去 -->
<to>
<!-- push到阿裡雲鏡像倉庫,如果是其它鏡像倉庫,将下面位址替換掉即可,ex: `Docker Hub` 的 `docker.io/zhengqing/xxx` -->
<!-- 鏡像名,命名格式為:Registry 倉庫位址/屬組/鏡像名:Tag名 -->
<image>
${docker.repostory}/${docker.repostory.namespace}/${project.artifactId}
</image>
<tags>
<tag>${docker.project.version}</tag>
<tag>latest</tag>
</tags>
<!-- 阿裡雲的使用者名和密碼也可以配置在 maven settings.xml檔案中(推薦) -->
<!--插件配置中的使用者密碼及鏡像庫位址在ci的環境變量中配置 -->
<auth>
<username>在阿裡雲上的賬号</username>
<password>阿裡雲注冊的密碼</password>
</auth>
</to>
<container>
<jvmFlags>
<jvmFlag>-Xms512m</jvmFlag>
<jvmFlag>-Xmn256m</jvmFlag>
</jvmFlags>
<environment>
<TZ>Asia/Shanghai</TZ>
</environment>
<useCurrentTimestamp>true</useCurrentTimestamp>
</container>
<!--允許使用 HTTP 協定連接配接 Registry 倉庫-->
<allowInsecureRegistries>true</allowInsecureRegistries>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
配置 module 的 pom
<parent>
<groupId>com.missyou</groupId>
<artifactId>missyou</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.missyou</groupId>
<artifactId>missyou_user_service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<build>
<finalName>missyou_user_service</finalName>
<plugins>
<!-- spring-boot-maven-plugin -->
<!-- maven-compiler-plugin -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
配置maven settings.xml檔案(推薦)
<pluginGroups>
<pluginGroup>com.google.cloud.tools</pluginGroup>
</pluginGroups>
<!--對應容器倉庫權限的賬号密碼-->
<servers>
<server>
<id>registry-vpc.cn-shenzhen.aliyuncs.com</id>
<username>xxx</username>
<password>xxx</password>
</server>
</servers>
配置 .gitlab-ci.yml
image: xxx.com/xxx-tools/cibase:0.5.0
variables:
MAVEN_OPTS: -Dmaven.repo.local=.m2/repository
BUILD_CI_NAME: $CI_COMMIT_REF_NAME-$CI_PIPELINE_ID
stages:
- build
- dev-release
cache:
key: one-key-for-all
paths:
- .m2/repository/
build:
stage: build
script: "mvn -U clean compile"
dev-release:
stage: dev-release
only:
- tags
- development-uat
- /^release-.*$/
when: manual
script:
- "mvn compile jib:build -Dregistry_url=$REGISTRY_URL -Dregistry_username=$REGISTRY_USERNAME -Dregistry_password=$REGISTRY_PASSWORD -Dci_pipeline_id=$BUILD_CI_NAME"
配置完畢後,使用如下指令編譯,并
自動 push 到倉庫中
:
mvn clean package -DskipTests jib:build
核心就是 jib:build,更多指令見文檔: https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#build-your-image
鑒權
根據錯誤日志可知連接配接 Registry 倉庫時需要鑒權
maven 報錯
解決-指令行
最粗暴的,在
執行 maven 指令時傳遞 Registry 倉庫的使用者名密碼
mvn clean package -DskipTests jib:build \
-Djib.from.auth.username=admin \
-Djib.from.auth.password=admin \
-Djib.to.auth.username=admin \
-Djib.to.auth.password=admin
由于
<from> 和 <to> 中的鏡像
可能不是來自于同一個 Registry 倉庫
,是以既要配置 from 的使用者名密碼,也要配置 to 的使用者名密碼。
執行完畢後,通過指令行,或者
可視化工具
,檢視
是否被 push 上去
(此處我使用的工具是
Harbor
)
解決-配置檔案
使用指令行方式每次執行都要輸入那麼長一串指令,這樣實在是不友善。另一種方法是
在 pom.xml 檔案直接将使用者名密碼配置進去
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.8.0</version>
<configuration>
<from>
<image>harbor.jitwxs-inc.com/base/java:8-jdk-alpine</image>
<auth>
<username>my_username</username>
<password>my_password</password>
</auth>
</from>
<to>
<image>harbor.jitwxs-inc.com/sample/${artifactId}:v1</image>
<auth>
<username>my_username</username>
<password>my_password</password>
</auth>
</to>
<allowInsecureRegistries>true</allowInsecureRegistries>
</configuration>
</plugin>
即
給 from 和 to 标簽都加上 <auth> 标簽
,但是這種方式實在是
不夠優雅
,因為
将使用者名密碼寫死在代碼中會帶來安全性問題
合适的方法
合适的方法是配置
在 Maven 的 settings.xml 配置檔案中
,在
<servers> 标簽中新增一個 <server> 節點
,
配置 Registry 倉庫的使用者名密碼
。
<servers>
...
<server>
<id>harbor.jitwxs-inc.com</id>
<username>admin</username>
<password>admin</password>
<configuration>
<email>[email protected]</email>
</configuration>
</server>
</servers>
配置完畢後,再執行次指令驗證下:
mvn clean package -DskipTests jib:build
不想單獨輸入 jib:build
如果你
不想單獨輸入 jib:build
,你可以
把 jib 綁定到 Maven 指令中
,在
maven插件中添加
如下的
<executions>
标簽即可。
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
...
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
mvn package 指令
就會自動建構鏡像
工作中
maven 中 pom 中标簽含義
檢視百度網盤