これは、なにをしたくて書いたもの?
以前、Jib Coreを使ってDockerイメージを作ってみました。
Jib Coreで、Dockerコンテナイメージを作ってみる - CLOVER🍀
これでJibの基本的なところはわかった…ことにして、今度はJib Maven Pluginを使ってDockerイメージを作ってみたいと思います。
Jib Maven Plugin
文字通り、Jibの機能が使えるMaven Pluginで、DockerまたはOCIイメージを作ることができます。
https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin
作成したイメージは、コンテナレジストリにアップロードしたり、Dockerデーモンに送ったり、tarファイルにしたりできます。
それでは、使っていってみましょう。
環境
今回の環境は、こちらです。
$ java --version openjdk 11.0.6 2020-01-14 OpenJDK Runtime Environment (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1) OpenJDK 64-Bit Server VM (build 11.0.6+10-post-Ubuntu-1ubuntu118.04.1, mixed mode, sharing) $ mvn --version Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 11.0.6, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "4.18.0-25-generic", arch: "amd64", family: "unix"
また、Jib Maven Pluginは2.1.0を使用します。
サンプルアプリケーション
先に、お題となるサンプルアプリケーションが必要ですね。
こちらで作ったものを流用します。
Jib Coreで、Dockerコンテナイメージを作ってみる - CLOVER🍀
pom。RESTEasyは、最新版にしておきました。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.littlewings</groupId> <artifactId>jib-simple-jaxrs-server</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jdk-http</artifactId> <version>4.5.3.Final</version> </dependency> </dependencies> </project>
起動クラス+JAX-RSリソースクラス。
src/main/java/org/littlewings/jaxrs/Server.java
package org.littlewings.jaxrs; import java.io.IOException; import java.net.InetSocketAddress; import java.util.Optional; import java.util.concurrent.TimeUnit; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import com.sun.net.httpserver.HttpServer; import org.jboss.logging.Logger; import org.jboss.resteasy.plugins.server.sun.http.HttpContextBuilder; public class Server { public static void main(String... args) throws IOException { Logger logger = Logger.getLogger(Server.class); HttpServer server = HttpServer.create(new InetSocketAddress(8080), 10); try { HttpContextBuilder builder = new HttpContextBuilder(); builder.getDeployment().getActualResourceClasses().add(HelloResource.class); builder.bind(server); server.start(); logger.info("server start."); while (true) { try { TimeUnit.SECONDS.sleep(1L); } catch (InterruptedException e) { // ignore } } } finally { server.stop(0); logger.info("server stop."); } } @Path("hello") public static class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN) public String message(@QueryParam("value") String value) { return "Hello " + Optional.ofNullable(value).orElse("World") + "!!"; } } }
こちらを、Jibを使ってDockerイメージにしていきましょう。
Jib Maven Pluginを組み込む
まずは、なにも考えずにプラグインを組み込んでみます。
<build> <plugins> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <to> <image>kazuhira/jib-simple-jaxrs-server</image> </to> </configuration> </plugin> </plugins> </build>
「jib:dockerBuild」でDockerイメージを作成しましょう。
$ mvn compile jib:dockerBuild
どうやら、「gcr.io/distroless/java:11」をベースにしてイメージを作ったみたいです。
[INFO] Containerizing application to Docker daemon as kazuhira/jib-simple-jaxrs-server... [WARNING] Base image 'gcr.io/distroless/java:11' does not use a specific image digest - build may not be reproducible [INFO] Using base image with digest: sha256:c94feda039172152495b5cd60a350a03162fce4f8986b560ea555de4d276ce19 [INFO] [INFO] Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, org.littlewings.jaxrs.Server] [INFO] [INFO] Built image to Docker daemon as kazuhira/jib-simple-jaxrs-server [INFO] Executing tasks: [INFO] [==============================] 100.0% complete [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 8.328 s [INFO] Finished at: 2020-04-05T19:43:05+09:00 [INFO] ------------------------------------------------------------------------
確認。50年前のタイムスタンプのDockerイメージができました。
$ docker image ls | grep simple kazuhira/jib-simple-jaxrs-server latest cf8664e3692c 50 years ago 199MB
Dockerイメージの方も確認してみましょう。
$ docker container run -it --rm -p 8080:8080 kazuhira/jib-simple-jaxrs-server:latest Apr 05, 2020 10:50:26 AM org.littlewings.jaxrs.Server main INFO: server start.
OKですね。
$ curl localhost:8080/hello Hello World!!
では、少しずつ設定を変えていってみましょう。Jib Coreの時に習う感じします。
あと、Exampleも参考にするとよいでしょう。
タグを指定する
これは、単純にイメージ名の隣に「:」で区切ってタグを指定すればOKです。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> </configuration> </plugin>
ビルド後。
$ docker image ls | grep simple kazuhira/jib-simple-jaxrs-server 0.0.1 cf8664e3692c 50 years ago 199MB
ベースイメージを変更する
最初はデフォルトで使われるベースイメージ(Distroless)を使いましたが、ベースイメージを変更してみましょう。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> </configuration> </plugin>
from、imageで指定します。今回はAdoptOpenJDKにしました。
ところで、README.mdを見ていると、なにも指定がない場合のベースイメージは「gcr.io/distroless/java」が使われてると書かれて
いた割には最初にダウンロードされたのは「gcr.io/distroless/java:11」でした。
どうなっているんでしょう?
どうやら、Javaのバージョンを見てベースイメージを決めているようですね。
Java VMに渡すオプションを設定する
Jib Maven Pluginを使った場合は、ENTRYPOINTを直接指定することは少ないと思います。
代わりに、jvmFlagやmainClassなどを使用します。
entrypointという設定項目自体はあるのですが、jvmFlagsなどを設定しても無視されるそうな。
The command to start the container with (similar to Docker's ENTRYPOINT instruction). If set, then jvmFlags and mainClass are ignored. You may also set
INHERIT to indicate that the entrypoint and args should be inherited from the base image.*
では、jvmFlagを使ってみましょう。「-Xmx」を指定してみます。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> <container> <jvmFlags> <jvmFlag>-Xmx256m</jvmFlag> </jvmFlags> </container> </configuration> </plugin>
指定する時は、container配下にするようですね。
起動後にコンテナ内に入って確認してみると、Java VMへの引数が追加されていることが確認できますね。
$ docker container exec -it [コンテナ名] bash root@5de3f4e084f2:/# ps -ef | grep java root 1 0 27 11:20 pts/0 00:00:01 java -Xmx256m -cp /app/resources:/app/classes:/app/libs/* org.littlewings.jaxrs.Server root 36 26 0 11:20 pts/1 00:00:00 grep --color=auto java
なお、実行時にJava VMへの引数を指定したい場合は、JAVA_TOOL_OPTIONS環境変数を使うようです。
※ベースイメージがdistroless/javaの時に限るとは書いていますが…これはJavaのドキュメントにも記載のある環境変数ですが…
mainClassについては自動で検出するようですが、自分で指定することも可能です。
あと、プログラム自体の起動引数についてはargsで指定します。
ポートをEXPOSEする
ポートをEXPOSEするには、ports、portで指定します。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> <container> <jvmFlags> <jvmFlag>-Xmx256m</jvmFlag> </jvmFlags> <ports> <port>8080</port> </ports> </container> </configuration> </plugin>
確認。
$ docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bd8aa0836e4d kazuhira/jib-simple-jaxrs-server:0.0.1 "java -Xmx256m -cp /…" 5 seconds ago Up 2 seconds 8080/tcp busy_carson
イメージの作成時刻を変更する
作成時刻が50年前になっているのを変更するには、creationTimeを使用します。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> <container> <jvmFlags> <jvmFlag>-Xmx256m</jvmFlag> </jvmFlags> <creationTime>USE_CURRENT_TIMESTAMP</creationTime> <ports> <port>8080</port> </ports> </container> </configuration> </plugin>
「USE_CURRENT_TIMESTAMP」を使用すると、現在時刻でイメージが作成されます。
$ docker image ls | grep simple kazuhira/jib-simple-jaxrs-server 0.0.1 36ac8b04db85 2 minutes ago 228MB
ただし、現在時刻を使ってしまうと再現性を失うことになる点に注意してください。
Why is my image created 48+ years ago?
また、ISO 8601フォーマットで指定することもできます。
<plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> <container> <jvmFlags> <jvmFlag>-Xmx256m</jvmFlag> </jvmFlags> <creationTime>2020-01-15T10:30:45+09:00</creationTime> <ports> <port>8080</port> </ports> </container> </configuration> </plugin>
実体としては、DateTimeFormatter.ISO_DATE_TIMEでパースできる必要があります。
結果。
$ docker image ls | grep simple kazuhira/jib-simple-jaxrs-server 0.0.1 bf6479b69280 2 months ago 228MB
ビルドプロセスに組み込む
Mavenプラグインとして使っているのですし、package時にDockerイメージを作って欲しいものです。
以下を参考に、Mavenのビルドプロセスに組み込んでみましょう。
Profile「docker」にして、通常のパッケージングとは別にしてみました。
<profiles> <profile> <id>docker</id> <build> <plugins> <plugin> <groupId>com.google.cloud.tools</groupId> <artifactId>jib-maven-plugin</artifactId> <version>2.1.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>dockerBuild</goal> </goals> </execution> </executions> <configuration> <from> <image>adoptopenjdk:11-jre-hotspot</image> </from> <to> <image>kazuhira/jib-simple-jaxrs-server:0.0.1</image> </to> <container> <jvmFlags> <jvmFlag>-Xmx256m</jvmFlag> </jvmFlags> <creationTime>2020-01-15T10:30:45+09:00</creationTime> <ports> <port>8080</port> </ports> </container> </configuration> </plugin> </plugins> </build> </profile> </profiles>
「package」ゴール実行時に、「dockerBuild」するようにしてあります。
<executions> <execution> <phase>package</phase> <goals> <goal>dockerBuild</goal> </goals> </execution> </executions>
あとは、Profileを指定してビルドしましょう。
$ mvn -Pdocker package
こんなところでしょうか。
まとめ
Jib Maven Pluginを使って、Dockerイメージを作ってみました。
その他、WARに対して適用できたりしますし、設定も他にたくさんあるのですが、慣れればREADME.mdを見つつ使えそうな気がしますね。
今回は、こんなところで。