Clojure deployment to a production itself not a very complicated task, but with the Docker it becomes more flexible solution. You can deploy your app to the Amazon EC2 or even to Amazon EC2 Container Service just in minutes! In this example we have Ring web server listening on 3000 port an some public resources, like bootstrap css and js in resources/public folder, and application-specific settings in resources/settings folder.
Caution: your Ring web server should be configured to listen on 0.0.0.0 address in order to play nicely with docker.
First, assume we will deploy to the production compiled app as an executable uberjar file. So, you should make sure that your application can be compiled with command
lein uberjar
this will produce the new JAR file in the target folder, like following target/clojure-workshop-0.1.0-SNAPSHOT-standalone.jar.
Check that your executable is running
java -jar target/clojure-workshop-0.1.0-SNAPSHOT-standalone.jar
this should run your Clojure application. Keep in mind, that the entrypoint in your application is specified in project.clj file. In the clojure-workshop.core you should have private “main” function defined.
:main clojure-workshop.core
In case all above is okay, you can proceed with the Dockerfile creation.
FROM java:8-alpine
RUN mkdir -p /app /app/resources
WORKDIR /app
COPY target/uberjar/*-standalone.jar .
COPY resources/public resources/public
CMD java -jar clojure-workshop-0.1.0-SNAPSHOT-standalone.jar
EXPOSE 3000
Then build and tag your image
docker build -t mprokopov/clojure-workshop .
And try to launch
docker run -p 3000:3000 mprokopov/clojure-workshop
In case you did everything right you can enjoy your app response in browser http://localhost:3000. Keep in mind, that the docker assigns different internal network addresses for running containers, so you should configure your Ring web server to listen on the ‘0.0.0.0’ address.
Then your task is to deploy to the production. Let’s say you have a docker repository, for instance, in the Dockerhub. Push your image there.
docker push mprokopov/clojure-workshop
Spin off your virtual server instance and login to your remote server via ssh, ensure you have docker instance running with ‘docker ps’, if not, install docker service. Then we can continue
docker pull mprokopov/clojure-workshop
If you decide to have nice looking docker-composer.yaml, this could be your example how to create one:
services:
srv:
build: .
image: mprokopov/clojure-workshop
volumes:
- ./resources/settings:/app/resources/settings
ports:
- 3000:3000
restart: always
See that settings volume? In this way you can store your sensitive or permanent data outside of the ephemeral container to survive between container spin-offs.
docker-compose up -d
If you need nginx-proxy before your container you can enjoy jwilder/nginx-proxy container, then your docker-compose should include VIRTUAL_HOST env variable.
services:
srv:
build: .
image: mprokopov/clojure-workshop
environment:
VIRTUAL_HOST=mydomain.com
volumes:
- ./resources/settings:/app/resources/settings
ports:
- 3000:3000
restart: always
After this you can open http://mydomain.com and enjoy your Clojure application in production with nginx-proxy.