介绍
其实 jib 刚发布时就有关注, 但是一直没有用于生产, 原因有二
基于 https://github.com/spotify/docker-maven-plugin (原作者已经停止维护 docker-maven-plugin, 建议使用 https://github.com/spotify/dockerfile-maven )的原有流程跑的好好的, 没动力换成 jib
Google jib 一直没有发布 1.x , 担心其不稳定
先简单介绍一下: google jib https://github.com/GoogleContainerTools/jib/ 是 Google 于 18 年 7 月发布的一个针对 Java 应用的构建镜像的工具(支持 Maven 和 Gradle) , 好处是能够复用构建缓存, 能够加快构建, 减小传输体积(后文会详细讲解), 并且让 Java 工程师不需要理解 Docker 相关知识就可以简单构建镜像并且发布到指定 registry 里(不需要 docker build , tag, push)
本文会依次讲解三种 java 构建镜像的方法, 分别是 正统的 Dockerfile ,spotify/dockerfile-maven ,Google jib
附赠 https://github.com/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
详情参见 官方文档 https://github.com/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 是 (阿里开源的一个 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 / 命令列表 https://alibaba.github.io/arthas/commands.html 了解 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 中非快照部分放到一个层, 将快照部分放到一个层, 将源码编译后放到一个层...
参考资料
谷歌开源 Java 镜像构建工具 Jib
jib 自定义 entrypoint https://segmentfault.com/a/1190000016254151
jib 打包 docker 镜像实战 https://segmentfault.com/a/1190000016156009
Jib - Containerize your Maven project
来源: https://juejin.im/post/5c60c021f265da2dd37bf85b