Capsule | simple java deployment

The ultimate deployment package for standalone JVM apps.

See part 2 on Scaling!

In a nutshell, Capsule is a simple deployment package for standalone JVM apps. It defines a way to package an entire application into a single runnable jar and run it as easy as java -jar app.jar. Dependencies, system properties and JVM arguments are all taken care of. Gone are the days of platform-specific startup scripts, JVM flags and classpath nightmares.

Essentially, the Capsule project provides a Capsule.class (known as the Capsule Runner) which is set as the main class in the jar (the jar is now a capsule). You define all of your app’s configuration in the manifest file of your app. When you execute the capsule, the Capsule Runner will read the configuration options from the manifest file and subsequently setup and run your app accordingly. It will download and cache dependencies, set system properties, append JVM flags and build the class path, before finally executing your app. For a full list of capsule configration options see the reference. Capsule also supports reading of maven pom.xml (if you prefer this to the manifest file).

Solving the single deployment problem has been attempted before with tools such as the Maven’s Shade plugin and One-Jar, however none of these are as feature rich as Capsule.

Capsule Types

In the most basic form, a capsule can simply be a jar just containing the Capsule.class, the capsule classes (in its directory) and the manifest file:

capsule.jar/
 --Capsule.class
--capsule/
 --META-INF/MANIFEST.MF

This is known as the ‘empty’ capsule type. In the manifest you define the name of the app, and a set of one or more repositories. The Capsule Runner will download the app (after it finds it from one of the repos) and its dependencies in a cache directory, before executing it. The capsule directory containing Capsule’s classes is needed as it contains the code to pull dependencies etc. If you want to change the version of your app, you just need to change the entry in the manifest file and re-execute the capsule. Simple huh?

The ‘thin’ capsule type includes your actual app jar, and thus the Capsule Runner will not need to download it when executing (it will however need to download the dependencies, if there are any). If you want a new version of your app, you will need to rebuild the capsule with the new app.jar.

capsule.jar/
 --Capsule.class
--capsule/
 --META-INF/MANIFEST.MF
 --app.jar

The ‘fat’ capsule type also includes the dependencies and thus the Capsule Runner will not need to download anything (thus not requiring an internet connection, or needing the capsule/ directory).

capsule.jar/
 --Capsule.class
 --META-INF/MANIFEST.MF
 --app.jar
 --dependencyA.jar
 --dependencyB.jar

The type to choose is personal preference, although perhaps it is recommended beginners go for the fat capsule type. Note that, a capsule can also be packaged with a subset of the dependencies, with the remaining to be resolved at runtime. This is a capsule type somewhere inbetween thin and fat.

Overhead?

The fat capsule adds about 100ms to the startup time whilst an empty or thin capsule (one with external dependencies, downloaded at first launch), adds about 500ms to the launch time.

In terms of JAR size, fat capsules add negligible overhead, whilst empty and thin capsules add 1.5MB (for the code responsible to downloading and resolving the external dependencies) — but they don’t require the dependencies to be embedded in the JAR, so there’s overall savings in deliverable size.

Plugins

The community has provided some great plugins; maven (built by me☺), gradle and even leiningen!

With a maven project at hand, the capsule-maven-plugin can be easily included with as little as the following:

<plugin>
<groupId>sg.enixsoft</groupId>
<artifactId>capsule-maven-plugin</artifactId>
<version>${capsule.maven.plugin.version}</version>
<configuration>
<appClass>hello.HelloWorld</appClass>
<type>fat</type>
</configuration>
</plugin>
mvn package capsule:build

where the app’s main class is specified for the appClass. This will build a fat capsule type which can then be executed with the java command:

java -jar target/my-app-1.0-cap.jar

To add system properties, JVM arguments, modes and even integration with the maven-exec-plugin, see the full reference, or checkout the demo project.

Final Thoughts

Capsule reinstates the beauty of java; being able to run an app anywhere, effortlessly. Use Capsule to package your backend java app, and then run it within a Docker image to bring deployment harmony.

See part 2 on Scaling your Capsule on AWS!