CLOVER🍀

That was when it all began.

WildFly Maven Pluginでコンテナイメージを作成する

これは、なにをしたくて書いたもの?

これまでWildFly Maven Pluginをちょいちょいと使ってきているのですが、そういえばこれを使ってコンテナイメージを作ったことがないなと
思いまして。

情報も知らないので、確認がてら試してみることにしました。

wildfly:imageゴール

WildFly Maven Pluginでコンテナイメージを作成するには、wildfly:imageゴールを使います。

WildFly Maven Plugin – wildfly:image

これはWildFly Maven PluginでプロビジョニングしたWildFlyとデプロイメントから、コンテナイメージを作成およびpushするゴールです。

wildfly:imageゴールはpackageゴールを拡張したもので、WildFlyがプロビジョニングされデプロイメントのデプロイ後に
コンテナイメージのビルド、pushが行われます。

The image goal extends the package goal, building and pushing the image occurs after the server is provisioned and the deployment deployed in it.

実行はDockerのバイナリーに依存しているとされています。つまり、実行にはdockerコマンドが必要だということですね。

The image goal relies on a Docker binary to execute all image commands (build, login, push).

これはdockerBinaryというパラメーターでpodmanなどに代替することもできます。

なお、Bootable JARでパッケージングしても無視されるようです。

Note that if a WildFly Bootable JAR is packaged, it is ignored when building the image.

設定のサンプルはこちらです。

WildFly Maven Plugin – Build and push your application in a container image

それでは、簡単なJakarta EEアプリケーションを作成して試してみましょう。

環境

今回の環境はこちら。

$ java --version
openjdk 21.0.5 2024-10-15
OpenJDK Runtime Environment (build 21.0.5+11-Ubuntu-1ubuntu124.04)
OpenJDK 64-Bit Server VM (build 21.0.5+11-Ubuntu-1ubuntu124.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 21.0.5, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-51-generic", arch: "amd64", family: "unix"

アプリケーションを作成する

今回はJakarta RESTful Web Services(以降JAX-RS)を使った簡単なアプリケーションを作成することにします。

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>wildfly-maven-plugin-container-image</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.wildfly.bom</groupId>
                <artifactId>wildfly-ee-with-tools</artifactId>
                <version>35.0.0.Final</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>ROOT</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>5.1.1.Final</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    
                    <!-- あとで -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

WildFly Maven Pluginを追加し、wildfly:imageゴールを実行するように設定しています。これでmvn package時にコンテナイメージを
作成するようになります。

                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>

こちらはWildFly Glowを使うようにしているだけですが、この時点ではこのままいきます。

                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    
                    <!-- あとで -->
                </configuration>

JAX-RSの有効化。

src/main/java/org/littlewings/wildfly/RestApplication.java

package org.littlewings.wildfly;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/")
public class RestApplication extends Application {
}

JAX-RSリソースクラス。

src/main/java/org/littlewings/wildfly/HelloResource.java

package org.littlewings.wildfly;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class HelloResource {
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String message() {
        return "Hello World";
    }
}

動作確認しておきます。

$ mvn compile wildfly:dev

OKですね。

$ curl localhost:8080/hello
Hello World

これで準備は完了です。

WildFly Maven Pluginでコンテナイメージを作成する

では、コンテナイメージを作成しましょう。

以下のように設定しているので

                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>

mvn packageでコンテナイメージが作成できます。

$ mvn package

設定しない場合は、packageに続けてwildfly:imageを実行するとよいでしょう。

$ mvn package wildfly:image

実行すると、途中でこんな表示が出てきました。

[INFO] Generating Dockerfile /path/to/wildfly-maven-plugin-container-image/target/Dockerfile from base image quay.io/wildfly/wildfly-runtime:latest
[INFO] Building application image wildfly-maven-plugin-container-image:latest using docker.
[INFO] Executing the following command to build application image: 'docker build -t wildfly-maven-plugin-container-image:latest .'

quay.io/wildfly/wildfly-runtime:latestというのがベースイメージのようです。

Dockerfileも作成されるようです。

target/Dockerfile

FROM quay.io/wildfly/wildfly-runtime:latest
COPY --chown=jboss:root server $JBOSS_HOME
RUN chmod -R ug+rwX $JBOSS_HOME
COPY --chown=jboss:root ROOT.war $JBOSS_HOME/standalone/deployments/ROOT.war

コンテナイメージができました。デフォルトのイメージ名はアーティファクト名で、タグはlatestみたいですね。

[INFO] Successfully built application image wildfly-maven-plugin-container-image:latest

実行。

$ docker container run -it --rm -p 8080:8080 wildfly-maven-plugin-container-image:latest

確認。

$ curl localhost:8080/hello
Hello World

OKです。

コンテナの中身を見てみる

少しコンテナの中身を見てみましょう。

$ docker container run -it --rm -p 8080:8080 --entrypoint bash wildfly-maven-plugin-container-image:latest

/etc/os-release

$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.5 (Plow)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="9.5"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.5 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9"
BUG_REPORT_URL="https://issues.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.5
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.5"

Javaは、現時点では21でした。

$ java --version
openjdk 21.0.5 2024-10-15 LTS
OpenJDK Runtime Environment (Red_Hat-21.0.5.0.11-1) (build 21.0.5+11-LTS)
OpenJDK 64-Bit Server VM (Red_Hat-21.0.5.0.11-1) (build 21.0.5+11-LTS, mixed mode, sharing)

設定を変更してみる

ここからは少しWildFly Maven Pluginの設定を変えてみます。

イメージ名とタグを指定してみましょう。image-nametagで指定できます。

                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    <image-name>my-image</image-name>
                    <tag>0.0.1</tag>
                </configuration>

パッケージング。

$ mvn package

このようになりました。

[INFO] Successfully built application image my-image:0.0.1
JDKのバージョンを指定する

jdk-versionJDKのバージョンを指定できます。今回は21を指定。

                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    <jdk-version>21</jdk-version>
                </configuration>

パッケージング。

$ mvn package

途中の様子。

[INFO] Generating Dockerfile /path/to/wildfly-maven-plugin-container-image/target/Dockerfile from base image quay.io/wildfly/wildfly-runtime:latest-jdk21
[INFO] Building application image wildfly-maven-plugin-container-image:latest using docker.
[INFO] Executing the following command to build application image: 'docker build -t wildfly-maven-plugin-container-image:latest .'

ベースイメージがquay.io/wildfly/wildfly-runtime:latest-jdk21になりました。

その他

実際に使う時はこんなところでしょうか。

                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    <image-name>${project.artifactId}</image-name>
                    <tag>${project.version}</tag>
                    <jdk-version>21</jdk-version>
                </configuration>

レジストリーにpushする場合は、pushtrueにして、レジストリーを指定する場合はregistryを指定するようです。

                <configuration>
                    <overwrite-provisioned-server>true</overwrite-provisioned-server>
                    <discover-provisioning-info>
                        <version>35.0.0.Final</version>
                    </discover-provisioning-info>
                    <push>true</push>
                    <registry>my-registry</registry>
                </configuration>

registryを設定した場合、イメージ名にレジストリー名が入るようです。

ベースイメージについて

設定を見ていたのですが、ベースイメージは変更できないようです。

以下で固定されているようですね。

WildFly Runtime Image

先ほど少し中身を見ましたが、これはUBIのようです。

そしてjdk-versionを指定した時には、quay.io/wildfly/wildfly-runtime:latest-${jdk-version}がベースイメージになります。

https://github.com/wildfly/wildfly-maven-plugin/blob/v5.1.1.Final/plugin/src/main/java/org/wildfly/plugin/provision/ApplicationImageInfo.java#L81-L90

現時点では、11、17、21が指定できるようですね。パッチバージョンまで指定できてもいいと思うのですが…latest-の部分は変えられませんね。

このイメージのことは、「UBI9 runtime image」として紹介されています。

New WildFly S2I and Runtime Multi-arch Images

WildFly S2I (Source to Image) builder and runtime images documentation

wildfly-runtime」という名前なので最初はどういう存在なのかよくわからなかったのですが、WildFlyはあくまでプロビジョニングしたものを
使用し、こちらはUBIとOpenJDKが含まれたイメージだということですね。

wildfly-runtime自体の定義については、こちらを見るとよいと思います。
ベースイメージはregistry.access.redhat.com/ubi9/ubi-minimalのようです。

https://github.com/wildfly/wildfly-s2i/blob/main/wildfly-runtime-image/image.yaml

おわりに

WildFly Maven Pluginでコンテナイメージを作成してみました。

コンテナイメージの作成自体は簡単でしたが、使われているベースイメージがよくわからなかったのでいろいろ調べたりしてみました。

だいたい内容はわかったので、今後WildFlyでコンテナイメージを作る場合には使っていきましょう。