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.
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
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.");
}
}
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.
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. .. ..
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 the
wait 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.
If you want to operate everything from the command line, you can hit jib: dockerBuildor
docker: 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.
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.
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`.
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