Packaging and deployment of an entire Vert.x application

186 views
Skip to first unread message

Dai MIKURUBE

unread,
Sep 20, 2022, 4:51:10 AM9/20/22
to ve...@googlegroups.com
Hi,

I posted a similar question in StackOverflow, but let me re-post it here.

TL;DR, I wanted to know the popular packaging and deployment method of an entire Vert.x application (not deploying each Verticle), in real production use.


From official documents and third-party articles, I see some patterns to start an Vert.x application process, such as :

* Run through "mvn / gradle run(Mod)" from a source code directory
* Use the "vertx" command to "deploy" a verticle with .java files (how things are packaged, then?)
* Build a Fat JAR, and deploy it
* Embed Vert.x in another Java app http://vert-x.github.io/embedding_manual.html

Which of them (or anything else) is a popular approach expected to be applied in real production to package and deploy an entire Vert.x application?

I don't think many people are using "mvn / gradle run" in their real production environments, but many third-party articles explain that way...


Thanks.

--
Dai MIKURUBE
   dmik...@acm.org

Christopher Tate

unread,
Sep 20, 2022, 8:02:09 AM9/20/22
to vert.x
Hello Dai,

I like to build a directory, copy the source code, run mvn clean install to build a fat jar, rename the fat jar, then run the main verticle of the application using the java command and JAVA_OPTS configured in the container environment variable. You can see my Dockerfile here:

USER root
RUN install -d /root/src
COPY . /root/src
WORKDIR /root/src
RUN mvn clean install -DskipTests
RUN cp /root/src/target/*.jar /root/src/app.jar
CMD java $JAVA_OPTS -cp .:* org.computate.smartvillageview.enus.vertx.MainVerticle


The fat jar is built with this plugin in the pom.xml:

            <plugin>
                <groupId>io.reactiverse</groupId>
                <artifactId>vertx-maven-plugin</artifactId>
                <version>${vertx-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>vmp</id>
                        <goals>
                            <goal>initialize</goal>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <redeploy>true</redeploy>
                </configuration>
            </plugin>

Hopefully that helps!

Christopher Tate

Dai MIKURUBE

unread,
Sep 21, 2022, 5:16:06 AM9/21/22
to ve...@googlegroups.com
Thanks, Christopher!

Got it. I'm now expecting that a fat JAR ( + Docker) approach would be popular and a kind of de-facto standard in production Vert.x.

It was interesting for me in your example that you're specifying a Verticle class as a "Java main class" embedding Vert.x, not "io.vertx.core.Launcher" with the Verticle class as the "main Verticle" for the Launcher.

Is that "embedded" approach with creating a Vertx instance by itself so popular in production Vert.x users?  The Vert.x team did not seem to recommend that approach strongly for better and easier scaling...

  • You will have to manage scaling of your application manually by programmatically creating more instances of your servers. You will not be able to benefit from the -instances option of the vertx command or in the PlatformManager API.
  • You will need to manually ensure you do not have concurrent access to non thread-safe core objects in your application. The Vert.x platform would normally protect you against this.


2022年9月20日(火) 21:02 Christopher Tate <ct...@redhat.com>:
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/f79a5b50-1ebc-41f0-a5e7-808be04db389n%40googlegroups.com.


--
Dai MIKURUBE
   dmik...@acm.org

Christopher Tate

unread,
Sep 21, 2022, 8:40:09 AM9/21/22
to vert.x
Interesting, I can't seem to find a PlatformManager in the latest Vert.x 4 codebase. That looks like old Vert.x 3 documentation. I have found Vert.x deployed many different ways to be very scalable:

                DeploymentOptions deploymentOptions = new DeploymentOptions();
                deploymentOptions.setInstances(siteInstances);
                vertx.deployVerticle(MainVerticle.class, deploymentOptions).onSuccess(a -> {
                    LOG.info("Started main verticle. ");

I always integrate a Zookeeper Cluster Manager as well, so that I can scale the number of container pods up, and the requests are load balanced between the pods, and background tasks can also share the load of a long running task by sending events on the event bus to be processed by multiple pods:

        if(enableZookeeperCluster) {
            Vertx.clusteredVertx(vertxOptions).onSuccess(vertx -> {
                runner.accept(vertx);
                promise.complete();
            }).onFailure(ex -> {
                LOG.error("Creating clustered Vertx failed. ", ex);
                promise.fail(ex);
            });
        } else {
            Vertx vertx = Vertx.vertx(vertxOptions);
            runner.accept(vertx);
            promise.complete();
        }


Another way that I have deployed Vert.x that works quite well is without a Dockerfile at all, but with source-to-image builds on OpenShift. A BuildConfig can build reference the SITE_REPO_HTTPS straight from Github, and perform a build of the source code straight onto a ImageStreamTag provided by Red Hat "java:latest" (https://access.redhat.com/documentation/en-us/openjdk/11/html-single/using_openjdk_11_source-to-image_for_openshift/index):

  source:
    git:
      uri: '{{ SITE_REPO_HTTPS }}'
    type: Git
  strategy:
    sourceStrategy:
      from:
        kind: ImageStreamTag
        name: 'java:latest'
        namespace: openshift
    type: Source

Then my DeploymentConfig references the ImageStreamTag

  triggers:
    - imageChangeParams:
        automatic: true
        containerNames:
          - {{ SITE_NAME }}
        from:
          kind: ImageStreamTag
          name: '{{ SITE_NAME }}:latest'
          namespace: "{{ SITE_NAMESPACE }}"
      type: ImageChange
    - type: ConfigChange

I specify the zookeeper cluster configuration as environment variables, especially the CLUSTER_HOST_NAME and CLUSTER_PUBLIC_HOST_NAME I get automatically from a fieldRef provided by OpenShift so that the pods can cluster together properly.  I provide the JAVA_MAIN_CLASS which tells the java:latest image what to run, and I can specify the number of SITE_INSTANCES and WORKER_POOL_SIZE as well for when I create the verticle. Then I can scale both the number of pods in the cluster, and the number of instances per pod:

            - name: OPENSHIFT_SERVICE
              value: smart-village-view
            - name: CLUSTER_PORT
              value: '8081'
            - name: ZOOKEEPER_HOST_NAME
              value: zookeeper.smart-village-view.svc
            - name: ZOOKEEPER_PORT
              value: '2181'
            - name: CLUSTER_HOST_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
            - name: CLUSTER_PUBLIC_HOST_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
            - name: JAVA_MAIN_CLASS
              value: org.curriki.api.enus.vertx.MainVerticle
            - name: SITE_INSTANCES
              value: '2'
            - name: WORKER_POOL_SIZE
              value: '2'

Hope that helps!

Christopher Tate

Dai MIKURUBE

unread,
Sep 25, 2022, 10:10:19 PM9/25/22
to ve...@googlegroups.com
Thanks for the much detailed explanation, Christopher!

Got it. That could be old information... I even found that the Java package was "org.vertx.java.platform", not "io.vertx". It was in v2, not even v3.

Good to know about Vert.clusteredVertx. I'm not very familiar with ZooKeeper and OpenShift, but they would be a good starting point to investigate Vert.x clustering deeper. Let me try a deep dive.

In the example you showed, it was interesting for me that its MainVerticle.main() calls Vertx.vertx(), even while its MainVerticle.run() also calls Vertx.vertx() (or clusteredVertx()).


2022年9月21日(水) 21:40 Christopher Tate <ct...@redhat.com>:


--
Dai MIKURUBE
   dmik...@acm.org
Reply all
Reply to author
Forward
0 new messages