Build and push your application in a container image

The image goal allows you to build an application image that contains a server and your application. This application image contains your application ready to run on the cloud in a containerized platform such as Kubernetes.

The operations related to the image are executing using a Docker binary. This can be explicitly set with the <docker-binary> element. It can also be overridden with the wildfly.image.binary property. If no binary is defined in the configuration, an attempt will be made to determine a default binary. First docker is attempted to be resolved. If it cannot be resolved, then podman is attempted. If neither can be resolved an error will occur.

By default, the image goal will only build the application image. To push it to a container registry, you must configure the <push> element with to true.

Build an application image

The example below shows how to build an application image.

<project>
    <artifactId>my-app</artifactId>
    ...
    <build>
        ...
        <plugins>
            ...
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>6.1.0.Final</version>
                <configuration>
                    <feature-packs>
                        <feature-pack>
                            <!-- Latest released version -->
                            <location>wildfly@maven(org.jboss.universe:community-universe)</location>
                        </feature-pack>
                    </feature-packs>
                    <layers>
                        <!-- Galleon layer allows to trim the installed server to your needs. The 'jaxrs-server' 
                        contains the server content required to execute JAXRS applications -->
                        <layer>jaxrs-server</layer>
                    </layers>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
        ...
    </build>
...
</project>

Once mvn package is executed, a container image is available in with the docker binary with the name my-app:latest. The name of the image is based on the <artifactId> value of the Maven module.

You can then run the image locally using Docker:

docker run -p 8080:8080 my-app:latest

Push an application image to a container registry.

The example below shows how to configure the image goal to push the applicaition image to a container registry:

<project>
    <artifactId>my-app</artifactId>
    ...
    <build>
        ...
        <plugins>
            ...
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>6.1.0.Final</version>
                <configuration>
                    <feature-packs>
                        <feature-pack>
                            <location>wildfly@maven(org.jboss.universe:community-universe)</location>
                        </feature-pack>
                    </feature-packs>
                    <layers>
                        <layer>jaxrs-server</layer>
                    </layers>
                    <push>true</push>
                    <registry>quay.io</registry>
                    <group>${user.name}</group>
                    <registryId>quay-io</registryId>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
        ...
    </build>
...
</project>

When mvn package is executed, the image goal will build the image with the name quay.io/jdoe/my-app (jdoe being the name of the user running the Maven commands). Before the image is pushed, it will login to quay.io using the credentials specified by <registryId>. The <registryId> defines the name of a <server> in your settings.xml file which may include encrypted passwords. While there is a <user> and <password> option, using a server in your settings.xml is the preferred way to authenticate with your registry.

Configure the JDK version used by the application image.

For Bootable JAR server, the application image is based on the OpenJDK runtime image. For WildFly server installation, the application image is based on a runtime image provided by WildFly that contains all the runtimes required to run WildFly and your application.Push an application image to a container registry.

You can override the JDK version used, see the WildFly documentation for supported versions. The below example uses the Java 21 version of the image using the <jdk-version/> configuration property.

<project>
    <artifactId>my-app</artifactId>
    ...
    <build>
        ...
        <plugins>
            ...
            <plugin>
                <groupId>org.wildfly.plugins</groupId>
                <artifactId>wildfly-maven-plugin</artifactId>
                <version>6.1.0.Final</version>
                <configuration>
                    <feature-packs>
                        <feature-pack>
                            <location>wildfly@maven(org.jboss.universe:community-universe)</location>
                        </feature-pack>
                    </feature-packs>
                    <layers>
                        <layer>jaxrs-server</layer>
                    </layers>
                    <jdk-version>21</jdk-version>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>image</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
        ...
    </build>
...
</project>

Additional deployments

Additional deployments resolved from the project dependencies with the <included-dependencies/>, <excluded-dependencies/>, <included-dependency-scope/> and <excluded-dependency-scope/> configuration properties, see the package goal example, are added to the application image as well. As with the package goal they are copied to the standalone/deployments directory of the server. The image goal copies them in their own image layer after the server layer.

By default, the deployment scanner deploys the content of the standalone/deployments directory when the server starts. The scanner writes marker files into this directory and therefore requires a writable file system. For an immutable image, you can disable the deployment scanner and register the deployments as unmanaged deployments in the Galleon configuration used to provision the server, for example with a provisioning-file:

<installation xmlns="urn:jboss:galleon:provisioning:3.0">
    <feature-pack location="wildfly@maven(org.jboss.universe:community-universe)">
        <default-configs inherit="false"/>
        <packages inherit="false"/>
    </feature-pack>
    <config model="standalone" name="standalone.xml">
        <layers>
            <include name="jaxrs-server"/>
        </layers>
        <feature spec="subsystem.deployment-scanner.scanner">
            <param name="scanner" value="default"/>
            <param name="scan-enabled" value="false"/>
        </feature>
        <feature spec="deployment">
            <param name="deployment" value="my-app.war"/>
            <param name="content" value="[{path=deployments/my-app-1.0.0.war,relative-to=jboss.server.base.dir,archive=true}]"/>
            <param name="enabled" value="true"/>
        </feature>
    </config>
</installation>

The path refers to the file name of the resolved artifact, my-app-1.0.0.war in this example. The name of the deployment, my-app.war, is also used as the runtime name and determines the context root.