Native Clojure on Kubernetes, the fastest way.
Switch branches/tags
Nothing to show
Clone or download
Pull request Compare This branch is 9 commits ahead of jwhitlark:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/hey
Dockerfile
LICENSE
README.md
perf.sh
project.clj

README.md

clj-on-k8s-quickstart

Minimal HttpKit web server compiled into a 10 MB dockerized native binary.

Relevance

As somebody who used to be a hardcore systems guy but fell into the comfort and nicety of the JVM and later on the joy of Clojure, I have always been interested in a systems-oriented Clojure version (call it LLVM-Clojure, Clojure to C, whatever), which in itself is somewhat contradictory since the garbage collection and memory allocation that the JVM (very efficiently) does for us must be reimplemented. Expectedly, maybe because of the previous reason, no such Clojure systems implementation exists yet.

Graal has made a way possible. And probably, the best possible way.

No wonder Clojure communities are excited over this. Graal, with its native-image tool compiles bytecode to native machine versions, embedding the JVM and your code into a single binary native file that can be handled directly by the OS.

The next question is the need to reduce the size of the final executable. Enters Java 10 and its modules. So I started working, forked from clj-on-k8s-quickstart and built on top of it.

The product is a dockerized native webserver implemented in Clojure with all the abstraction it provides which stats up with no down time.

Instructions

  • Build your Docker image
docker image build -t clj-on-k8s/hey:0.0.2 .
  • Assuming you have a Kubernetes set up (and the image placed in the correct ECR)
kubectl run hello-clj --image clj-on-k8s/hey:0.0.2 --port 3000 --env="MY_NAME=Clojure" --labels name=hello-clj

This works for Minikube. This should also work in vanilla Docker.

  • Connect to the web server inside the container
kubectl port-forward $(kubectl get pods --no-headers -o name --selector "name=hello-clj") 3000:3000

Goals and Rational

Original goals

It's an exciting time.

Clojure has always been a clean and powerful language with nice interop with the JVM

Clojure.spec has added exciting capabilities that are very relevant to microservices.

With JDK9, the JVM has become modular, allowing us to greatly shrink the size of our images.

With JDK10, the JVM has become a much better docker citizen.

With Kubernetes, we now have a great platform to build microservices on.

Istio on K8s gives us new ways to easily visualize, monitor and trace our traffic flows between services. It also simplifies many security tasks, and gives us new abilities to control traffic.

Extra goals

Graal makes it possible extra-fast native Clojure programs

Important changes

I needed to switch from Ring/Jetty to HttpKit because of an Eclipse project class not found by Graal that I could not resolve. The class was indeed present in the produced Jar, but it looks like a more general problem with Graal. The Eclipse ecosystem is apparently affected by this.

Also I needed to get rid of several cryptographic signature checks that I had no time to fix.

Thanks!