JVM Deployment Options

Eric Normand · Updated April 25, 2018

If you're lucky, there comes a time in your Clojure app's life when it
will need to leave the comforts of the development environment and to
open its ports to the world. As a mature platform, the JVM has a lot
of server deployment options. While options, in general, are good,
they are intimidating. Some of the deployment options are of the
"multimillion-dollar enterprise certification" variety.

When you're working at a company, you usually inherit their deployment
system. And that's great because then you just do what they do. But
what if you are on your own? What are the options for deploying a
Clojure server?

Executables

Deployment options fall into two broad categories. The first is the
simplest: the application runs as an executable, just like other
servers you're familiar with. You can use all of the operating system
stuff you're used to, like turning it into a service that starts at
boot.

This is how I run most of my apps. I compile an executable uberjar and
use something like supervisord to keep them running.

Containers

The second option is a little more complex. You can actually deploy
your application to what's called a container. For instance, Wildfly is an application server container. Tomcat is a servlet
container.

Containers do two things that make them important.

They run multiple applications in a single JVM.

The container
isolates the different applications so they can load different
versions of the same class and can't access each other's
memory. You can write your application as if it were running in its
own JVM, without the downsides of requiring a lot of memory per
application.

They provide services such as web servers, database access, queues,
and schedulers.

Your applications can talk to each other using the
queues, share database connections, and tap into high-performance
web servers.

Now I'll go over some options and how they fit into this scheme. This
is a non-exhaustive list of my recommendations.

Heroku

Heroku works out of the box with Clojure. It can detect if you're
using Leiningen. It will build an uberjar and deploy it to their cloud
as an executable. That means you'll want a built-in web server like Jetty, Netty, http-kit, or aleph. There's a Boot buildpack.

Heroku has a free tier and is affordable from there. You can also get other services like queues,
databases, email sending, etc. Deploying to Heroku is as easy as git push heroku master. It's very easy to get something running.

AWS Elastic Beanstalk

Amazon Web Services provides a container service called Elastic Beanstalk. You
upload a WAR (Web Application Archive)--basically a JAR file with
deployment information in it--and AWS will deploy it to Tomcat for
you. With Elastic Beanstalk, you only pay for the AWS resources you
use. You're running on EC2 and you can connect to the other services
they provide.

Hosting on a server

You can run your own server. This gives you complete control at the
cost of having to maintain a server. Servers are not that easy! There
are security concerns all the time.

I've had good luck running on Ubuntu using supervisord for
executable applications. People often use systemd. I've also used Wildfly as an application server.

Microservices

If you're going to be developing a microservices application, you
probably want an application container. JVMs take a lot of memory
each. Being able to share that across services is important. Also,
containers often have a messaging system that you can use out of the
box.

Immutant

Immutant is a full-fledge, enterprise grade application server
container for Clojure apps. It leverages Wildfly and provides
Clojure wrappers for a host of services offered directly in the
container. I highly recommend it. The setup is easy and the developers
are very responsive.

Docker

You can run Clojure apps in Docker containers. It works, and certainly
if you've only got a small number of JVM apps, this may be a great
option. But I'm a little worried about memory usage when you start
deploying many dockerized JVMs. Here is a good description of the setup for a web app. There are Docker images for lots of Clojure systems, including Immutant.

OSv

I've never run OSv, but it could be an interesting option if you're
willing to go bleeding edge. OSv is a tiny OS that can run JVM
applications. OSv runs directly on the hypervisor, so it removes a
huge layer of abstraction, meaning it's leaner and faster than running
a JVM on top of Linux.

Other resources

Conclusions

The many deployment options can be overwhelming, but really the
abundant choices are a blessing. The JVM is a mature platform that
finds itself in a wide variety of situations, from small hobby
projects to billion-dollar enterprise applications.

I've seen a lot of people turned off of Clojure because of the JVM,
and I think that's a real shame. The JVM does have its warts, and it
has a history, but on the whole it's a great platform. That's why I
created JVM Fundamentals for Clojure. Please check it
out if you're considering avoiding Clojure because of the JVM.

One of the cool things about the JVM is the Just-in-Time compiler
(JIT). It's a way to optimize code at runtime based on the abundant
information that running code gives you. We'll look at it next time!

Footer CTA

Get the newsletter for free

The PurelyFunctional.tv Newsletter is a weekly email to inspire functional programmers.

Enter your email address to receive emails about Clojure and Functional Programming. These include the weekly newsletter and other great offers. You can unsubscribe any time.