vertx.createHttpServer().requestHandler(function (request) {
request.response().end("Hello world");
}).listen(8080);
Vert.x Docker Images
Execute Vert.x applications in Docker containers.
Introduction
Docker lets you deploy applications inside lightweight and isolated software containers. Applications run side by side in isolated Linux containers. If you never used Docker before check this online tutorial.
Vert.x provides Docker images that you can use to run your applications. Two Docker images are provided:
-
vertx/vertx3
is the base image you need to extend to run your own application -
vertx/vertx3-exec
is providing thevertx
command to your system without having to installvert.x
yourself.
The images are available from Docker Hub.
This guide presents how to use these two images but also how to automate Docker image creation using Maven, generate Fabric8 metadata and use fat jars.
The base image
The base image (vertx/vertx3
) lets you run your vert.x application in a Docker container. For this, you must extend the image to deploy your own application - i.e. create your own Dockerfile
inheriting from vertx/vertx3
. Your application is then launched using the vertx
command (but in the container).
Deploying a JavaScript verticle in a docker container
Let’s start with a simple JavaScript verticle such as:
Create in the same directory a Dockerfile
with the following content:
# Extend vert.x image (1)
FROM vertx/vertx3
# Set the name of the verticle to deploy (2)
ENV VERTICLE_NAME hello-verticle.js
# Set the location of the verticles (3)
ENV VERTICLE_HOME /usr/verticles
EXPOSE 8080
# Copy your verticle to the container (4)
COPY $VERTICLE_NAME $VERTICLE_HOME/
# Launch the verticle (5)
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]
1 | First extend the image provided by vert.x |
2 | Set the name of the verticle |
3 | It sets the location in the container where the verticle file is placed |
4 | Copy the verticle files |
5 | Instructions to launch the verticle |
Then do build the image, just launch:
docker build -t sample/vertx-javascript .
Then, run it with:
docker run -t -i -p 8080:8080 sample/vertx-javascript
To see the result, open a browser to http://localhost:8080 or http://192.168.59.103:8080 if your are using boot2docker.
The container is launched with the '-t -i` flags meaning interactive. Stop the container by hitting CTRL+C . More details about the Docker run command are available here. |
You may have noticed the EXPOSE 8080
in the Dockerfile
and the -p 8080:8080
in the run
command. The first one is an optional information telling that the application wants to listen the port 8080. The second one is mandatory and instructs docker to forward the port 8080 from the host to the 8080 of the container.
You may also have noticed the convoluted way to launch the application. Instead of calling vertx directly, it uses sh -c along with exec . sh -c is to turn around a Docker limitation not expanding variables in CMD . This way the launched shell does. More details on the Docker builder documentation. exec is to make the vertx command process replace the shell, so that it gets pid 1 and receives signals, like SIGTERM when running docker stop . Without exec the shell keeps running along with the vertx command process, and the vertx command does not get signals, thus preventing graceful shutdown. |
Deploying a Groovy verticle in a docker container
Running a groovy verticle in a docker container is not much different. Instead of the hello-verticle.js
from the previous example, we now have a hello-verticle.groovy
:
vertx.createHttpServer().requestHandler({ request ->
request.response().end("Groovy world")
}).listen(8080)
So, in the Dockerfile
we just change the verticle file name:
# Extend vert.x image
FROM vertx/vertx3
# Set the name of the verticle to deploy
ENV VERTICLE_NAME hello-verticle.groovy
# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles
EXPOSE 8080
# Copy your verticle to the container
COPY $VERTICLE_NAME $VERTICLE_HOME/
# Launch the verticle
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]
The build and run instructions are very close to the previous ones:
> docker build -t sample/vertx-groovy .
....
> docker run -t -i -p 8080:8080 sample/vertx-groovy
Deploying a Ruby verticle in a docker container
Running a groovy verticle in a docker container is not much different. Instead of the hello-verticle.js/groovy
from the previous examples, we now have a hello-verticle.rb
:
$vertx.create_http_server().request_handler() { |request|
request.response().end("A ruby world full of gems")
}.listen(8080)
So, in the Dockerfile
we just change the verticle file name:
# Extend vert.x image
FROM vertx/vertx3
# Set the name of the verticle to deploy
ENV VERTICLE_NAME hello-verticle.rb
# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles
EXPOSE 8080
# Copy your verticle to the container
COPY $VERTICLE_NAME $VERTICLE_HOME/
# Launch the verticle
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]
The build and run instructions are very close to the previous ones:
> docker build -t sample/vertx-ruby .
....
> docker run -t -i -p 8080:8080 sample/vertx-ruby
Deploying a Java verticle in a docker container
So, now let’s see how to deploy a Java verticle. Again it’s not different from the previous examples, except that we copy the verticle jar file to the container. Let’s take the following verticle:
package io.vertx.sample.hello;
import io.vertx.core.AbstractVerticle;
public class HelloVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
vertx.createHttpServer().requestHandler(request -> {
request.response().end("Hello Java world");
}).listen(8080);
}
}
Let’s now imagine that this verticle is packaged into the target/hello-verticle-1.0.-SNAPSHOT.jar
jar file. So the Dockerfile
needs to copy this file but also gives to vert.x the verticle class name:
# Extend vert.x image FROM vertx/vertx3 # (1) ENV VERTICLE_NAME io.vertx.sample.hello.HelloVerticle ENV VERTICLE_FILE target/hello-verticle-1.0-SNAPSHOT.jar # Set the location of the verticles ENV VERTICLE_HOME /usr/verticles EXPOSE 8080 # Copy your verticle to the container (2) COPY $VERTICLE_FILE $VERTICLE_HOME/ # Launch the verticle WORKDIR $VERTICLE_HOME ENTRYPOINT ["sh", "-c"] CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]
1 | Unlike the previous examples, here we set the verticle class name and the jar file |
2 | The jar file is copied. |
Build and run instructions do not change:
> docker build -t sample/vertx-java .
....
> docker run -t -i -p 8080:8080 sample/vertx-java
Configuration
The previous `Dockerfile`s did not configure vert.x. Let’s see how such configuration can be added.
Configuring the Java Virtual Machine
You can configure the Java Virtual Machine using the JAVA_OPTS
environment variable. So in the Dockerfile
adds:
ENV JAVA_OPTS "-Dfoo=bar"
VERTX_OPTS
System variables specific to vert.x can be configured using the VERTX_OPTS
environment variable:
ENV VERTX_OPTS "-Dvertx.options.eventLoopPoolSize=26 -Dvertx.options.deployment.worker=true"
Classpath
You can configure the classpath of the application using either the -cp
parameter of the vert.x command or the CLASSPATH
environment variable:
ENV CLASSPATH "/usr/verticles/libs/foo.jar:/usr/verticles/libs/bar.jar:"
Logging
To configure the logging.properties
file (that let you customize JUL loggers`), set the VERTX_JUL_CONFIG
environment variables:
COPY ./logging.properties $VERTICLE_HOME/ (1)
ENV VERTX_JUL_CONFIG $VERTICLE_HOME/logging.properties (2)
1 | Copy your logging.properties file |
2 | Set the VERTX_JUL_CONFIG environment variable |
Clustering
You can provide your own cluster.xml
file, and add it to the classpath. To build a dynamic classpath from all the file contained in $VERTICLE_HOME
you can use:
COPY ./cluster.xml $VERTICLE_HOME/
# ...
CMD [export CLASSPATH=`find $VERTICLE_HOME -printf '%p:' | sed 's/:$//'`; exec vertx run $VERTICLE_NAME"]
Notice the export CLASSPATH=…;
part in the CMD
instruction. It builds the value of the CLASSPATH
variable from the content of the $VERTICLE_HOME
directory. This tricks is useful to compute large and dynamic classpath.
Build Docker Images with Maven
There are a couple of Maven plugins to build your Docker images during your Maven build process. This example uses the docker-maven-plugin from Spotify.
First, create your Java project as usual. So your sources are located in src/main/java
… Then create a src/main/docker
directory and create a Dockerfile
inside:
.
├── pom.xml
├── src
│ └── main
│ ├── docker
│ │ └── Dockerfile
│ └── java
│ └── io
│ └── vertx
│ └── example
│ └── HelloWorldVerticle.java
├── target
In the pom.xml
file add the following plugin configuration
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.2.8</version>
<executions>
<execution>
<id>docker</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
<!-- Configure the image name -->
<imageName>sample/vertx-hello</imageName>
<resources>
<resource>
<targetPath>/verticles</targetPath>
<directory>${project.build.directory}</directory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</resource>
<!-- don't forget to also add all the dependencies required by your application -->
</resources>
</configuration>
</plugin>
The plugin copies the listed content into target/docker
. Each resource is copied into the set targetPath
. So edit the src/main/docker/Dockerfile
and add the following content:
FROM vertx/vertx3
ENV VERTICLE_HOME /usr/verticles
ENV VERTICLE_NAME io.vertx.example.HelloWorldVerticle
COPY ./verticles $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec vertx run $VERTICLE_NAME -cp $VERTICLE_HOME/*"]
It’s basically the same content as we saw above. The copy is a bit different as the plugin have placed files in the same directory as the Dockerfile
.
Once configured the image is built using: mvn clean package
Build Docker Images for Fabric 8
Fabric 8 is an open source set of micro-services that run on top of Kubernetes and OpenShift V3 to provide management, continuous delivery and iPaas facilities. You can execute vert.x application on top of Fabric 8 by packaging them into a Docker image. However, additional metadata is required. In this example, we are going to use the docker-maven-plugin from Roland Huß.
Let’s set up the following structure:
.
├── pom.xml
├── src
│ └── main
│ ├── docker
│ │ └── assembly.xml
│ └── java
│ └── io
│ └── vertx
│ └── example
│ └── HelloWorldVerticle.java
└── target
Unlike the maven plugin from Spotify, this plugin takes an assembly.xml
as input. The file lists all the files that need to be copied to the docker container such as:
<assembly>
<dependencySets>
<dependencySet>
<includes>
<include>:${project.artifactId}</include>
</includes>
<outputDirectory>.</outputDirectory>
</dependencySet>
</dependencySets>
</assembly>
The rest of the Dockerfile configuration is given in the `pom.xml
file. Add the following plugin to the pom.xml
file:
<plugin>
<groupId>org.jolokia</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.11.5</version>
<executions>
<execution>
<id>build</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<images>
<image>
<name>${docker.image}</name>
<build>
<from>vertx/vertx3</from>
<tags>
<tag>${project.version}</tag>
</tags>
<ports>
<port>8080</port>
</ports>
<command>vertx run io.vertx.example.HelloWorldVerticle -cp
/usr/verticles/${project.artifactId}-${project.version}.jar
</command>
<assembly>
<mode>dir</mode>
<basedir>/usr/verticles</basedir>
<descriptor>assembly.xml</descriptor>
</assembly>
</build>
</image>
</images>
</configuration>
</plugin>
To configure the container more finely, check the manual. All the instructions we put in the Dockerfile
can be set from the plugin.
The previous pom.xml file use a properties called docker.image setting the image name. Don’t forget to set it in your pom.xml` file. |
Once you have this configuration in place, we need a second plugin to generate the metadata required by Fabric8:
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>fabric8-maven-plugin</artifactId>
<version>2.1.4</version>
<executions>
<execution>
<id>json</id>
<phase>generate-resources</phase>
<goals>
<goal>json</goal>
</goals>
</execution>
<execution>
<id>attach</id>
<phase>package</phase>
<goals>
<goal>attach</goal>
</goals>
</execution>
</executions>
</plugin>
Once set up, you can build your docker image with: mvn clean package
. It creates the kubernates.json
file required by Fabric8. Then push your image on the Docker Registry provided by Fabric8:
docker push $DOCKER_REGISTRY/sample/vertx-hello
Don’t forget to set the DOCKER_REGISTRY
url to point on the registry managed by Fabric8. The last step is to apply it with:
mvn io.fabric8:fabric8-maven-plugin:2.1.4:apply
The executable image
The vertx/vertx3-exec
image provides the vertx
command to the host. So no need to install vert.x on your machine, you can just use this docker image.
For instance:
> docker run -i -t vertx/vertx3-exec -version
3.6.2
To run a verticle:
docker run -i -t -p 8080:8080 \
-v $PWD:/verticles vertx/vertx3-exec \
run io.vertx.sample.RandomGeneratorVerticle \
-cp /verticles/MY_VERTICLE.jar
This command mounts the current directory (PWD
) into /verticles
and then launch the vertx run
command. Notice the -cp
parameter reusing the /verticles
directory.
Customizing the stack
The vertx/vertx3-exec
image provides the default "full" Vert.x stack. You may want to customize this stack and create your own exec image. First, create a vertx-stack.json
file:
{
"variables": {
"vertx.version": "3.3.3"
},
"dependencies": [
{
"groupId": "io.vertx",
"artifactId": "vertx-web",
"version": "${vertx.version}",
"included": true
},
{
"groupId": "io.vertx",
"artifactId": "vertx-lang-js",
"version": "${vertx.version}",
"included": true
}
]
}
You can list any dependency you need, not just the Vert.x artifacts (refer to the Stack Manager documentation for details).
Then write a Dockerfile
for your custom executable image:
FROM vertx/vertx3-exec (1) COPY vertx-stack.json ${VERTX_HOME}/vertx-stack.json (2) RUN vertx resolve && rm -rf ${HOME}/.m2 (3)
1 | Extend the Vert.x executable image |
2 | Replace the stack file in the Vert.x command installation |
3 | Resolve dependencies |
You should know be able to build your custom executable image:
docker build -t mycompany/my-vertx3-exec .
And run your verticle:
docker run -i -t -p 8080:8080 \
-v $PWD:/verticles mycompany/my-vertx3-exec \
run io.vertx.sample.RandomGeneratorVerticle \
-cp /verticles/MY_VERTICLE.jar
Deploying a fat jar
It is also possible to deploy a Vert.x application packaged as a fat jar into a docker container. For this you don’t need the images provided by Vert.x, you can directly use a base Java image. Let’s have a look.
First, be sure your application is packaged as a fat jar. Then, use the following Dockerfile
:
FROM openjdk:8-jre-alpine (1)
ENV VERTICLE_FILE hello-verticle-fatjar-3.0.0-SNAPSHOT-fat.jar (2)
# Set the location of the verticles
ENV VERTICLE_HOME /usr/verticles
EXPOSE 8080
# Copy your fat jar to the container
COPY target/$VERTICLE_FILE $VERTICLE_HOME/ (3)
# Launch the verticle
WORKDIR $VERTICLE_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec java -jar $VERTICLE_FILE"] (4)
1 | Extend the image providing OpenJDK 8, use the one you want |
2 | Set the VERTICLE_FILE to point on the fat jar |
3 | Copy the Fat jar from target. Change it if you don’t use Maven. |
4 | Launch the application using the java executable (instead of vertx |
It’s basically the same Dockerfile
as before. However, this time we extend java:8
instead of the vertx/vertx3
image. Then we copy the fat jar to the container, and launch it with the java
executable. All the configuration settings presented above are still valid.
Build and run the container with:
> docker build -t sample/vertx-java-fat .
....
> docker run -t -i -p 8080:8080 sample/vertx-java-fat