[JAVA] I tried to integrate Docker and Maven / Netbean nicely using Jib

I used Docker to create a Java environment for a while, but by the way, Maven creates a nice Docker image without writing a Dockerfile Jib I thought there was, and tried it. mojikyo45_640-2.gif

To be honest, I didn't pay much attention to it because I thought "Isn't it okay to write a Dockerfile normally?", But it's surprisingly convenient to use.

This time, I created a Java 11 environment with my main development environment, Mac + NetBeans, so I will describe how to do it. There was also a little trap, so I'll list that as well.

The finished product is below. https://github.com/koduki/example-jib

Creating a program for execution

Obviously, first write the code to be executed. Anything is fine, but once it looks like the following. It seems that public static void main is necessary as an endpoint.

public class Main {

    public static void main(String[] args) {
        System.err.printf("%s %s, %s %s" + System.lineSeparator(),
                System.getProperty("os.name"),
                System.getProperty("os.version"),
                System.getProperty("java.vm.name"),
                System.getProperty("java.vm.version")
        );
        System.out.println("Hello World.");
    }
}

Addition of Jib

Then let's add Jib anyway. It's as easy as adding a plugin to pom.xml.

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>1.0.0-rc2</version>
    <configuration>
        <from>
            <image>openjdk:11-jdk-slim</image>
        </from> 
        <to>
            <image>example-jib</image>
        </to>
        <container>
            <jvmFlags>
                <jvmFlag>-Xmx512m</jvmFlag>
                <jvmFlag>-Xdebug</jvmFlag>
            </jvmFlags>
        </container>
    </configuration>
</plugin>

For details, refer to Official Document, but there are some points. First, the to / image tag, which specifies the image name after build. And the from / image tag, which specifies the original image.

from / image is optional, in which case gcr.io/distroless/java is used as the default. However, since this environment is Java8, if you want to use any JDK such as Java11, you need to specify it explicitly, so be careful. With container, you can specify various things such as JVM options. Although not specified this time, use extraDirectory You can also do the equivalent of ʻADD` in the Dockerfile. However, the files in src / resouces are automatically added to the container, so it may not come into play so much.

If you want to play with the container in a complicated way, I think it would be easier to create a base image with Jib and use it as FROM.

Image build by Jib

Next is the image build.

$ mvn compile jib:dockerBuild

This alone will skip the creation of the Dockerfile and create an image. You should be able to see that the image is created properly as shown below.

% docker images|grep example-jib      
example-jib                    latest              8ec59091042c        49 years ago        491MB

In the case of dockerBuild, the image is registered in the local Docker daemon, but if you want to push directly to a remote such as DockerHub, use jib: build.

Also, if you are using Docker for Mac at this timing, the following error may occur.

Failed to execute goal com.google.cloud.tools:jib-maven-plugin:1.0.0-rc2:dockerBuild (default-cli) on project example-jib: Build to Docker daemon failed, perhaps you should make sure Docker is installed and you have correct privileges to run it -> [Help 1]

This is simply because Jib hasn't found the docker daemon, but if you hit the docker command directly, it works normally? ?? ?? It was like that. However, it is easy to reveal the seeds, and when calling docker for Mac directly from the command line, it is not necessary to specify DOCKER_HOST, so it was not included in the environment variable. Why, it is necessary to add DOCKER_HOST to the environment variable with the following command etc.

export DOCKER_HOST=unix:///var/run/docker.sock

I'd like you to mention this area in the README, but I wonder if it was too obvious for those who are familiar with it and no one cares about it. .. ..

Running container from maven

Next is the execution of the container from Maven. You can do docker run normally, but that is inconvenient because you have to start up the terminal separately. .. .. So I tried to make this also possible from Maven.

Jib itself seems to be build-specific and there seems to be no mechanism to execute it, so I put in another plugin called fabric8io / docker-maven-plugin I did. That's why I added the following to pom.xml.

<plugin>
    <groupId>io.fabric8</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.28.0</version>
    <configuration>
        <showLogs>true</showLogs>
        <images>
            <image>
                <name>example-jib</name>
                <run>
                    <log>
                        <enabled>true</enabled>    
                    </log>
                    <wait>
                        <exit>0</exit>
                    </wait>
                </run>
            </image>
        </images>
        <keepContainer>false</keepContainer>
    </configuration>
</plugin>

See the official documentation for more details, but specify the image to run with ʻimage / name`. If you need volume or port, it's like adding to run.

The points are showLogs, ʻimage / run / log / enabled, ʻimage / run / wait / exit. If this area is not specified, the execution result will not be output to the standard output. showLogs and ʻimage / run / log / enabledare options for outputting the execution result as a log. However, this is not enough, and if you do not register something in thewait tag, the execution will end instantly and nothing will appear on the screen. Therefore, ʻexit 0 to confirm normal completion is checked.

When you do this, you get:

% mvn docker:start   
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< cn.orz.pascal:example-jib >----------------------
[INFO] Building example-jib 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- docker-maven-plugin:0.28.0:start (default-cli) @ example-jib ---
[INFO] DOCKER> [example-jib:latest]: Start container ec75063ae514
ec7506> Linux 4.9.125-linuxkit, OpenJDK 64-Bit Server VM 11.0.1+13-Debian-2bpo91
ec7506> Hello World.
[INFO] DOCKER> [example-jib:latest]: Waited on exit code 0 964 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  5.142 s
[INFO] Finished at: 2019-01-13T20:09:12-08:00
[INFO] ------------------------------------------------------------------------

Since the OS part of the execution result is Linux instead of Mac, you can see that it is properly started in the container.

Integration with Maven / Netbeans build process

If you want to operate everything from the command line, you can hit jib: dockerBuildordocker: start` every time, but usually you develop using IDE, right? It's Java. With NetBeans, you can register a custom goal of maven, but the feeling of using the IDE is not good, so I will set it a little more integrated.

Execute jib: dockerBuild in "Build" of NetBeans

In the case of NetBeans, it is common to create a build image with "Build" in the menu. The appropriate jar for Java and war for Java EE will be built with this menu. Why overwrite Maven's package phase so that the Docker image is still generated.

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
...
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>dockerBuild</goal>
            </goals>
        </execution>
    </executions>
</plugin>

I added the execution tag to the plugin settings part earlier. Now you can run jib: dockerBuild with mvn package as below.

% mvn package
[INFO] Scanning for projects...
...
[INFO] --- jib-maven-plugin:1.0.0-rc2:dockerBuild (default) @ example-jib ---
[INFO] 
[INFO] Containerizing application to Docker daemon as example-jib...
[INFO] The base image requires auth. Trying again for openjdk:11-jdk-slim...
[INFO] 
[INFO] Container entrypoint set to [java, -Xmx512m, -Xdebug, -cp, /app/resources:/app/classes:/app/libs/*, cn.orz.pascal.example_jib.Main]
...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  19.345 s
[INFO] Finished at: 2019-01-13T20:07:28-08:00
[INFO] ------------------------------------------------------------------------

NetBeans Build calls Maven's package phase, so NetBeans side can just do Build from the menu normally without setting a custom goal.

Execute docker: start with "Run" of NetBeans

Next is the execution of the container. In fact, there is no execution equivalent phase in Maven's standard life cycle. ʻOrg.codehaus.mojo: exec-maven-plugin: 1.5.0: exec` is actually executed, but since it is only executed by directly specifying the goal, how to hook this on Maven side I didn't know if it should be done.

So, Maven decided to give up and change only the NetBeans settings. To customize standard actions such as Run, edit nbactions.xml directly under the project.

<?xml version="1.0" encoding="UTF-8"?>
<actions>
    <action>
        <actionName>run</actionName> 
        <goals>
            <goal>docker:start</goal>
        </goals>
    </action>
</actions>

Now if you run Run from NetBeans, docker: start will be executed instead of ʻexec: exec`.

Summary

Here's a summary of how to integrate Docker, Maven and NetBeans nicely with Jib. If you are developing in Java, it is somewhat convenient to be able to do various things integrated with the IDE rather than the CLI. I'm glad I could do this because there is no sense of integration with custom goals.

This time I wrote CLI-based Java, but it seems that Java EE can be imaged with Jib without any problem, so I would like to investigate that area next time.

I wonder if this is a step forward for using Docker at work.

Then Happy Hacking!

Recommended Posts

I tried to integrate Docker and Maven / Netbean nicely using Jib
I tried to integrate AWS I oT button and Slack
I tried to build an environment using Docker (beginner)
I tried using Wercker to create and publish a Docker image that launches GlassFish 5.
I tried to build the environment little by little using docker
[Rails] I tried to implement "Like function" using rails and js
What is Docker? I tried to summarize
I introduced WSL2 + Ubuntu to Window10 and tried using GDC, DMD, LDC
I tried to make my own transfer guide using OpenTripPlanner and GTFS
I tried using Docker for the first time
I tried using Junit on Mac VScode Maven
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to link grafana and postgres [docker-compose]
[Android] I quit SQLite and tried using Realm
I made a Docker container to run Maven
I tried to link JavaFX and Spring Framework.
Push the image to docker hub using Jib
I tried to implement a server using Netty
[JDBC ③] I tried to input from the main method using placeholders and arguments.
I tried to read and output CSV with Outsystems
I tried using Gson
I tried to summarize the state transition of docker
Bad Gateway came out when I tried to connect Grafana and InfluxDB on Docker
I started MySQL 5.7 with docker-compose and tried to connect
I tried using TestNG
I tried using YOLO v4 on Ubuntu and ROS
I tried using Galasa
I tried using Docker Desktop for Windows on Windows 10 Home
Rails6 I tried to introduce Docker to an existing application
I tried to chew C # (reading and writing files)
[Rails 6.0, Docker] I tried to summarize the Docker environment construction and commands necessary to create a portfolio
I tried to make an introduction to PHP + MySQL with Docker
I tried to collect and solve Ruby's "class" related problems.
I tried to summarize the basics of kotlin and java
I tried to verify this and that of Spring @ Transactional
I tried to introduce UI animation to Pokedex using Poké API
I tried using Hotwire to make Rails 6.1 scaffold a SPA
I tried to make Java Optional and guard clause coexist
I tried to create React.js × TypeScript × Material-UI on docker environment
I tried to summarize personally useful apps and development tools (development tools)
I tried to build the environment of WSL2 + Docker + VSCode
I tried to summarize personally useful apps and development tools (Apps)
I tried using Dapr in Java to facilitate microservice development
I tried to create a padrino development environment with Docker
I tried to get started with Swagger using Spring Boot
I tried using azure cloud-init
I tried the Docker tutorial!
I tried using Apache Wicket
I tried using Java REPL
I tried BIND with Docker
I tried to verify yum-cron
multi-project docker build using jib
[Metal] I tried to figure out the flow until rendering using Metal
I tried to build the environment of PlantUML Server with Docker
I tried connecting to MySQL using JDBC Template with Spring MVC
[Unity] I tried to make a native plug-in UniNWPathMonitor using NWPathMonitor
I tried to build a simple application using Dockder + Rails Scaffold
I tried to see if Koalas and Elasticsearch can work together
I tried to summarize the methods of Java String and StringBuilder
I tried to make it an arbitrary URL using routing nesting
I tried to display the calendar on the Eclipse console using Java.