概念
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>admin@jitwxs-inc.com</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 中标签含义
查看百度网盘