I have several web apps written in Clojure with Compojure and Ring. Until today I used a manual process that used an rsync.sh script that took me a minute per deploy. Yuck! Today I implemented two different two methods. One requires a manual “make deploy” command and the other uses a local git hook on my development laptop for an automatic deployment. Both of these methods also use my old rsync.sh script to copy changed files, but the process is automated.
Makefile
I added a deployment target to the project’s Makefile:
deploy:
./rsync.sh
ssh nonroot@MYDOMAIN.com 'bash -s' < run.sh
This assumes that you have an account "nonroot" on the server that you run web apps with. The run.sh file kills the old web app process and starts a new process; the file looks like this:
#! /bin/bash
ps aux | grep -e 'MYAPPNAME' | grep -v grep | awk '{print $2}' | xargs -i kill {}
(cd APP_DIRECTORY; nohup lein trampoline run prod > out.log&)
Substitute the name of your app for MYAPPNAME: go to your server and run "ps aux" and find a chacter string that uniquely identifies the process that needs to be stopped. Let me make this clear with an example. On my sever I did a ps aux and see the line:
nonroot 10444 0.0 7.0 1438456 95484 ? Sl May30 3:13 java -classpath /home/nonroot/knowledgebooks.com/test:/home/nonroot/knowledgebooks.com/test:/home/...
Here I would substitute "knowledgebooks" for MYAPPNAME.
I use lein with trampoline to run my web apps. I run Ubuntu on my servers and the killall command works fine. You will want to manually test this on your server and/or read the docs for killall.
Using a git post-commit hook
For some projects I don't want a separate step of running "make deploy" so I create a local git post-commit hook. I start by creating the file (and setting execute permissions on it) ~/.git/hooks/post-commit that looks like:
./rsync.sh
ssh nonroot@MYDOMAIN.com 'bash -s' < run.sh
This file post-commit uses the same run.sh file that I use for Makefile deployments.
Now, when I do a git commit, the deployment to my server is automatic.
If you are not familiar with using rsync, here is a quick start. My script rsync.sh (in each project directory) looks like:
rsync -e "ssh" -avz --delete --delete-excluded --exclude-from=./rsync_exclude ~/GITHUB/MYAPPDIRECTORY nonroot@MYDOMAIN.com:/home/nonroot/MYAPPDIRECTORY/ and the rsync_exclude file looks like:
.git
myfocus-clj.i*
target