随着容器的出现让Java开发人员比以往任何时候都更接近“编写一次,到处运行”的工作流程,特别这两年以spring-boot为基础构建起来的项目,使得交付变得更加简单。
One-JAR的魅力在于:
- 可以用
java -jar
机制执行。 - 能够包含应用程序需要的 所有文件 —— 也就是说, 包括原始形式(未展开)的类和资源。
- 拥有简单的内部结构,仅仅用
jar
工具就可以被装配起来。 - 对原来的应用程序不可见 —— 也就是说,无需修改原来的应用程序,就可以把它打包在 One-JAR 档案文件内部。
但这些就够了吗?
当然不,集约化交付后,之前你的系统是运行在虚拟机中,首先要docker中快速跑起来吧?如何快速动态扩容?如何快速回滚?
我是开发人员而非容器专家能不能别让我来维护修改dockerfile(它太复杂了)?
下面带着这些疑问,我给大家介绍3款工具,工具的好坏,重要的看自己的喜好。
目录
1. docker-maven-plugin
2016-4月份由Spotify开源的,当前版本v1.1.1,官方介绍ref
介绍
一个Maven插件,用于构建和上传docker镜像
历程
这个插件是Spotify使用的最初的Maven插件,用于从Java服务中构建DOCKERr镜像。它最初创建于2014,当我们第一次开始试验Docker。这个插件能够基于pom.xml文件中的配置为您生成一个Dockerfile,用于FROM映像、添加ADD/COPY等内容。
Spotify随着时间的推移,我们意识到,从Java项目中构建DOCKERr镜像最简单的方法是让开发人员编写DOCKFILE文件。这个插件在生成Dockerfile、将项目目录复制到“.ing”目录以作为Docker构建上下文等等方面的行为最终导致了与用户之间的许多不必要的混淆,这些混淆源于引入额外的抽象和对配置的需要。最重要的是Docker提供的东西。
这导致创建了用于构建docker映像的第二个Maven插件,dockerfile-maven,我们认为它为使用来自Maven的Docker提供了一个更简单的思维模型,原因都在dockerfile-maven的README中列出。
默认情况下,该插件通过访问localhost:2375来连接本地docker,可以通过设置DOCKER_HOST 环境变量来连接docker.
DOCKER_HOST=tcp://<host>:2375
在POM中声明构建信息
此示例创建一个名为example的新镜像,将项目的jar文件复制到镜像中,并设置运行jar的入口点。更改版本到最新的标签版本。
<build>
<plugins>
...
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<configuration>
<imageName>example</imageName>
<baseImage>java</baseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
<!-- copy the service's jar file from target into the root directory of the image -->
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
...
</plugins>
</build>
参数解释:
- imageName:镜像的名称,可以通过${project.groupId}/${project.artifactId}:${project.version} 动态制定镜像名称。当然也可以在前面加上镜像地址,比如127.0.0.1:5000,以声明将构建好的镜像存储在本地
- baseImage: 基础镜像,这里是相当于Dockerfile的FROM java
- resources 下的配置:构建时会生成docker文件夹,这里指生成文件夹的内容来源,包含了mvn clean package 之后的target的文件和生成的jar包。
使用Dockerfile
为了使用Dockerfile,必须在pom的文件中通过dockerDirectory来指明Dockerfile文件的所在目录。如果配置了dockerDirectory,baseImage,maintainer,cmd和entryPoint配置将忽略。下面的配置会将dockerDirectory的内容拷贝值${project.build.directory}/docker,使用resouces元素可以拷贝其他的文件,比如生成jar包文件。
<build>
<plugins>
...
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<configuration>
<imageName>example</imageName>
<dockerDirectory>docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
...
</plugins>
</build>
用法
生成一个镜像
mvn clean package docker:build
将生成的镜像推送到镜像注册中心
mvn clean package docker:build -DpushImage
如果推送制定tags 的镜像
mvn clean package docker:build -DpushImageTag
绑定docker命令到maven phases
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<execution>
<id>tag-image</id>
<phase>package</phase>
<goals>
<goal>tag</goal>
</goals>
<configuration>
<image>my-image:${project.version}</image>
<newName>registry.example.com/my-image:${project.version}</newName>
</configuration>
</execution>
<execution>
<id>push-image</id>
<phase>deploy</phase>
<goals>
<goal>push</goal>
</goals>
<configuration>
<imageName>registry.example.com/my-image:${project.version}</imageName>
</configuration>
</execution>
</executions>
</plugin>
可以通过一下命令跳过docker构建的阶段
- DskipDockerBuild 跳过镜像构建
- DskipDockerTag 跳过镜像tag设置
- DskipDockerPush 跳过镜像推送
- DskipDocker 跳过所有的镜像构建目标
删除一个名称为foobar的镜像
mvn docker:removeImage -DimageName=foobar
获取完成的配置选项列表
mvn com.spotify:docker-maven-plugin:<version>:help -Ddetail=true
使用私有镜像中心
为了将镜像推送到私有的镜像注册中心,docker需要在镜像tag之前用注册中心的地址作为前缀。比如需要推送my-image到registry.example.com,那么这个镜像需要命名为registry.example.com/my-image
最简单的方法就是在<imageName>中配置:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<imageName>registry.example.com/my-image</imageName>
这样,当你通过命令docker:build -DpushImage
或者docker:push
推送镜像时,docker引擎会将镜像推送到registry.example.com.
当然你可以在docker:build命令中通过 docker:tag -DpushImage
对创建的镜像加上私有镜像注册中心的地址,如不配置,则会推送到默认的镜像中心,即Docker hub;你也可如下这样配置:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<imageName>my-image</imageName>
...
</configuration>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<execution>
<id>tag-image</id>
<phase>package</phase>
<goals>
<goal>tag</goal>
</goals>
<configuration>
<image>my-image</image>
<newName>registry.example.com/my-image</newName>
</configuration>
</execution>
</executions>
</plugin>
认证
支持三种认证方式:
读取本地配置文件,自动认证
从1.0.0版本之后,docker-maven-plugin插件会自动读取到docker-cli的认证配置,默认在~/.dockercfg 和~/.docker/config.json,而无需额外的配置
GCR认证
如果本机配置DOCKER_GOOGLE_CREDENTIALS的环境变量,则会使用GCR认证。
Server认证
也可以在maven的settings.xml配置认证信息:
<servers>
<server>
<id>docker-hub</id>
<username>foo</username>
<password>secret-password</password>
<configuration>
<email>[email protected]</email>
</configuration>
</server>
</servers>
在pom.xml则通过如下配置关联上述server id
<plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>VERSION GOES HERE</version>
<configuration>
[...]
<serverId>docker-hub</serverId>
<registryUrl>https://index.docker.io/v1/</registryUrl>
</configuration>
</plugin>
</plugins>
以上三种配置方式中,通过读取客户端默认配置的优先级更高。
在server配置中加密密码
为了不在配置文件中不暴露明文密码,可以使用maven加密功能对密码进行加密,通过{ }方式都认为是被加密的密码
<servers>
<server>
<id>docker-hub</id>
<username>foo</username>
<password>{gc4QPLrlgPwHZjAhPw8JPuGzaPitzuyjeBojwCz88j4=}</password>
</server>
</servers>
2.dockerfile-maven-plugin
上面讲过,Spotify的第二个版本,官方介绍ref
- 不要做任何花哨的事。dockerfile是如何构建DOCKER项目;这就是插件使用的内容。它们是强制性的。
- 使DOCKER构建过程与Maven构建过程集成。如果绑定默认阶段,则在键入mvn package时,会得到docker映像。当您键入
mvn deploy
时,您的镜像会被推送。 - 让目标记住你在做什么。您可以键入
mvn dockerfile:build
和mvn dockerfile:tag
和稍后的mvn dockerfile:push
无问题。这也消除了对诸如mvn dockerfile:build -DalsoPush
之类的东西的需求;相反,您可以只说mvn dockerfile:build dockerfile:push
。 - 与Maven构建集成。您可以依赖于另一个项目中的一个项目的DOCKERr镜像,而Maven将按照正确的顺序构建项目。当您想要运行涉及多个服务的集成测试时,这是有用的。
约束
这个插件需要Java 7或更高版本和Apache Maven 3或更高版本。要运行集成测试或在实践中使用插件,需要一个docker环境。
示例
<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>spotify/foobar</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
对应的docker镜像可以是:
FROM openjdk:8-jre
MAINTAINER David Flemström <[email protected]>
ENTRYPOINT ["/usr/bin/java", "-jar", "/usr/share/myservice/myservice.jar"]
# Add Maven dependencies (not shaded into the artifact; Docker-cached)
ADD target/lib /usr/share/myservice/lib
# Add the service itself
ARG JAR_FILE
ADD target/${JAR_FILE} /usr/share/myservice/myservice.jar
它可以带来什么?
1.更快的建造时间,这个插件允许您更一致地利用Docker缓存,通过让您在映像中缓存Maven依赖项,极大地加快了构建的速度。它还鼓励避免maven-shade-plugin
,这也大大加快了构建。
2.一致的构建生命周期
mvn package
mvn dockerfile:build
mvn verify
mvn dockerfile:push
mvn deploy
3.依赖docker镜像上的其他服务,您可以依赖于另一个项目的Docker信息,因为这个插件在构建Docker映像时附加项目元数据。只需将此信息添加到任何项目
4.使用依赖Dockerfiles的其他docker工具
你的项目是这样的:
a/
Dockerfile
pom.xml
b/
Dockerfile
pom.xml
现在您可以使用这些项目与Fig或docker-compose或一些其他系统与Dockerfiles合作。例如,docker-compose.yml
:
service-a:
build: a/
ports:
- '80'
service-b:
build: b/
links:
- service-a
授权,ref
配置,更多
3. jib-maven-plugin
google 于2018-7开源的,官方介绍ref
目标
- 快速,快速部署您的更改。JB将应用程序分成多个层,从类中分离依赖项。现在,您不必等待DOCKER重建整个Java应用程序——只需部署更改的层即可。
- 可重复,使用相同的内容重建容器图像总是产生相同的镜像。永远不要触发不必要的更新。
- 无后台,减少你的CLI依赖关系。从Maven或Gradle内部构建你的docker镜像并推到你选择的任何注册表中。不再写Dockerfiles 档和调用docker build/push。
快速开始
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>0.9.11</version>
<configuration>
<to>
<image>myimage</image>
</to>
</configuration>
</plugin>
...
</plugins>
</build>
...
</project>
构建镜像
mvn compile jib:build
把镜像直接构建到本地docker中
mvn compile jib:dockerBuild
把镜像直接构建到本地磁盘(target/jib-image.tar)
mvn compile jib:buildTar
这样,可以从本地启动
docker load --input target/jib-image.tar
绑定生命周期
<plugin>
<groupId>com.google.com.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
...
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
你就可以运行mvn package
导出一个Docker context
mvn compile jib:exportDockerContext -DjibTargetDir=my/docker/context/
可以使用docker build image
docker build -t myimage my/docker/context/
其他参数说明,更多
最后,工具没有好坏之说,但个人推荐使用jib-maven-plugin,功能特性上稍稍丰富一些,另外就是google的魅力。