fatjar deployment best practice

838 views
Skip to first unread message

bern

unread,
May 10, 2016, 8:01:43 AM5/10/16
to vert.x
hi,

we are using vertx with docker and would like to use a fat jar deployment. the same jar file holds all verticles... 
my question is what would be the best practice for deploying the jar?
should I deploy a "main verticle" that deploys the other verticles in the same jar? for instance:

CMD ["vertx run service:com.dv.verticles.MainVerticle -cp /usr/verticles/MyJar-fat.jar -conf /usr/verticles/com.dv.verticles.MainVerticle.json"]


or should I run the vertx command twice with 2 different verticle names?

CMD ["vertx run service:com.dv.verticles.Verticle1 -cp /usr/verticles/MyJar-fat.jar -conf /usr/verticles/com.dv.verticles.Verticle1.json"]

CMD ["vertx run service:com.dv.verticles.Verticle2 -cp /usr/verticles/MyJar-fat.jar -conf /usr/verticles/com.dv.verticles.Verticle2.json"]

Thanks,

Tim Fox

unread,
May 10, 2016, 8:30:39 AM5/10/16
to ve...@googlegroups.com
Is this just one service, or a collection of services all in the same jar? (I'd caution against building more than one microservice into the same artifact as that's tightly coupling the builds of the different services which kind of goes against the microservices ethos).

If it's one service and that service is made up of multiple verticles then it probably makes sense to have a main verticle which makes sure the composing verticles are all started correctly.

Note that you can still use -instances even with a main verticle if you require more instances of your main. You can also control the number of instances you deploy programmatically from the config you pass in.

One strange thing from your example below. You seem to be running the "fat jar" with vertx run. The whole point of fat jars is they don't need vertx to run them, so this seems a bit odd. For an example of fatjars take a look at the maven verticle or gradle verticle examples in the examples repo.
--
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.
Visit this group at https://groups.google.com/group/vertx.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/e8125d44-ce19-40e4-83ea-74285289ef42%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

bern

unread,
May 10, 2016, 9:05:14 AM5/10/16
to vert.x
Hi Tim,

Yes, this is just one service in the same jar (HTTP service) with a few verticles.

I'm using a "fat jar" deployment because the verticle has other dependencies, so it made sense to wrap them in "one" jar. 
so if I understand correctly the best practice would be using something like (from the gradle example) instead of using the vertx command:

"java -jar build/libs/gradle-verticle-3.2.1-fat.jar"

Isn't this just the same as running a vertx as a self-hosted embedded program? Am I not losing other vertx goodies such as clustering capabilities this way? or How would I go about deploying another micro-service that is consuming messages on a shared topic on the EventBus?

Maybe I'm wrong about it but I'm trying to look at vertx as an infra for creating many microservices when each micro-service runs under vertx. This way it seems like each micro-service would have it's own isolated process (which is not necessarily a bad thing).

Tim Fox

unread,
May 10, 2016, 9:12:56 AM5/10/16
to ve...@googlegroups.com
On 10/05/16 14:05, bern wrote:
Hi Tim,

Yes, this is just one service in the same jar (HTTP service) with a few verticles.

I'm using a "fat jar" deployment because the verticle has other dependencies, so it made sense to wrap them in "one" jar.

Putting all your verticles in one jar is just a jar, it's not as fatjar. A fatjar has all your verticles plus all the jar dependencies including the Vert.x jars packaged into the single jar too. The idea with a fatjar is you can run it anywhere where java is installed with java -jar and you don't need to have vertx pre-installed there.


so if I understand correctly the best practice would be using something like (from the gradle example) instead of using the vertx command:

"java -jar build/libs/gradle-verticle-3.2.1-fat.jar"

I'm not saying that a fatjar is better or worse than running with vertx. But running with vertx is not a fatjar deployment.



Isn't this just the same as running a vertx as a self-hosted embedded program? Am I not losing other vertx goodies such as clustering capabilities this way? or How would I go about deploying another micro-service that is consuming messages on a shared topic on the EventBus?

Whether you package and run your service as a fatjar or using vertx makes absolutely no difference to it's capabilities and functionality. It's simply a packaging/deployment choice. Some people prefer one method over the other.



Maybe I'm wrong about it but I'm trying to look at vertx as an infra for creating many microservices when each micro-service runs under vertx. This way it seems like each micro-service would have it's own isolated process (which is not necessarily a bad thing).

Whether you run with vertx or as a fatjar they both live in their own isolated process. There is no difference there.

Ravi Luthra

unread,
May 10, 2016, 9:18:50 PM5/10/16
to vert.x
In our case, we're primarily avoiding the FAT JAR concept while using Docker and instead we're using a gradle task to put all the dependencies into a folder:

task copyVertxLibs(type: Copy) {
    into "docker/rest/lib"
    from configurations.compile
}
This has the major advantage of keeping your docker images extremely small. If your dependencies don't change, and you add these libs in the Dockerfile like this:
COPY lib /apps/hugo-rest/lib

Then you have the major advantage of this:

Step 9 : COPY lib /apps/hugo-intake/lib

 ---> Using cache

 ---> 384a0ae02818


If anyone changes a dependency, then clearly you'll have a changed dockerfile.
The one trick to this is that you'll need to ensure that any "in-company" jar files are NOT included in this copy if they have the tendency to change a lot.

Finally, our team is opting to running Java directly and using the Launcher class:
CMD ["java -cp .:lib/* io.vertx.core.Launcher run bootup.js --cluster --conf conf.json"]

bootup.js is a small javascript verticle that starts the others.

Arnold Schrijver

unread,
May 11, 2016, 5:48:23 AM5/11/16
to vert.x
@Ravi: Am I right in stating that your primary advantage is in the shorter development cycle you get due to no using FAT jars, rather than getting smaller image sizes per se? In the end the images you push to remote servers will be similar in size (unless maybe if you pushed the dependencies to a named base image).

I am using fat jars in my Docker images, but for local development (mostly unit-testing) these are not needed. The CD pipeline will auto-create fat jars and images before commencing with integration and acceptance testing, and the overhead in fat jar-creation + docker layer is not all that high. In my microservices architecture I try to minimize the dependencies per microservice. It is nothing like in ye olde WAR world where war-files reach whopping sizes. My fat jars are between 30 and 60 MB each which is quite manageable.

But I have been considering your approach previously. In the end I found it easier having to manage single fat jar artifacts rather than many individual files (also because the Go.CD build server I use is not all that good in handling artifact transfer between pipelines).

Charles Vuillecard

unread,
Aug 28, 2018, 10:31:17 AM8/28/18
to vert.x
As Ravi said you should avoid a fat jar for tow main reasons :

1 - Packaging a fat jar take a long time and means that all your jar will be unziped in one jar. You'll obtain an heavy jar (most of the time more than 100 mb if it's not more than 200mb). Therefore imagine the time to package 10 jars as fat jar.
2 - The choice of deploying all verticles from another or a main depends of your needs. if all of your verticles are contained in the same jar and are used exclusively by it, you can basically simply create a main in which you deploy all of the verticles you need to use.

- Feedback of my experience if it can help -

I am actually working on an application totally decentralized with a micro-services approach. 
(Working context :  Each module of the application is a service and must be a standalone application dealing datas with others services using clustering through hazelcast in tcp using ssl.)

The packaging produces one jar for one service containing a consumer verticle to receive messages from the world and reply after have finished the work asked.
Each service as a jar is actually simply run with the command : java -jar serviceName.jar

The problem is simple : 
1 - when you create a fatjar you create an heavy jar (it was about 230 mb on my project ! But now the problem is solved and now i just package a zip of 60mb which is unzipped in a common library directory when deployed), 
2 - if you construct a fat jar for each module of your app because of vertx or other dependencies, using maven you'll take a long time of packagingSo in my use case i would have to create a fatjar for each service which is bad for a fast and reactive deployment of one or more/multiple services

My analyse to solve this problem of packaging :

Consider these tow points at first to think about how i can :
1 - Discrease the time of packaging and avoid the creation of a fat jar.
2 - Providing Mutualisation of dependencies in one repository (maven local repository in DEV mode and a configuration directory in PROD mode just using the maven jar plugin to configure the classpath of each jar to point this directory)

More details about the solution i chose with maven :
1 - Create a module "configuration" holding all the necessary (vertx dependencies, hazelcat, logging, neo4j, spring, neo4j-spring-data, hibernate-ogm-neo4j whith jpa or whatever you need as a common dependency)
2 - Create a profile "ZIP" or with another name  you choose with the "maven assembly plugin" to package all the common dependencies in one archive (used uniquely in PROD)the configuration 
3 - Use the maven jar plugin to add a classpath prefix to each service or module depending of 'configuration' module.

With this solution :
- In DEV mode, you can directly use your local maven repository as classpath to configure the maven jar plugin (It's a usefull trick because the maven build is faster and it solves classpath problems, but don't do this in Production !)
- In PRODUCTION mode, you give the destination directory as a prefix for the classpath (It could be an URL even if i don't see the interest), so all MANIFEST files of the jars packaged will be automatically configured to have a classpath pointing to the configuration directory where the zip is unpacked.

NOTE : The difference between a zip of jars and a fat jar (with all classes of all your common dependencies unpacked) is terribly big. You discrease about by 3 the size of your package, and therefore your build is faster.

Asher Tarnopolski

unread,
Aug 29, 2018, 5:24:28 AM8/29/18
to vert.x
packaging a 120M fat jar with jenkins/gradle takes 18 sec for us

Charles Vuillecard

unread,
Aug 31, 2018, 10:07:04 AM8/31/18
to ve...@googlegroups.com
That’s a great time ;) just for the challenge because of your answer :
I build all the services as standalone jars and a zip configuration in 14 sec.
I don’t need fatjar anymore for the reasons we gave in the last post with ravi. My zip contains only jars configuration without applicative logic and is actually 60mb without optimization (cleaning of dependencies’s content).
And as i said in my last comment, the classpath is constructed when the Service jar is packaged, so no need to give a classpath in parameter to run the  jar (imagine if your host is hacked and the attaccker just replaces your classpath in overriding one class of your ˋfat jar’.

Fat jar is bad. Mutualisation is better ;)

Le mer. 29 août 2018 à 11:24, Asher Tarnopolski <ata...@gmail.com> a écrit :
packaging a 120M fat jar with jenkins/gradle takes 18 sec for us

--
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.
Visit this group at https://groups.google.com/group/vertx.
Reply all
Reply to author
Forward
0 new messages