There’s a great post about using clojure with docker.
I followed
the post with a twist. I used boot-alpine
image[1] and docker-compose
instead of Vagrant
.
Here’s the final configuration that worked.
# file docker-compose.yml
version: '2'
services:
bootclj:
command: boot dev
image: clojure:boot-alpine
ports:
- 9007:9007
- 9009:9009
- 9011:9011
- 3000:3000
volumes_from:
- m2
working_dir: /opt/src
m2:
command: echo "m2 container ready!"
image: alpine
volumes:
- /root/.m2
- ./:/opt/src
; file build.boot
(deftask development []
(task-options!
cljs {:optimizations :none
:source-map true
:compiler-options {:devcards true}}
start-repl {:ip "0.0.0.0" :port 9007}
cljs-repl {:nrepl-opts {:bind "0.0.0.0" :port 9009}}
reload {:on-jsload 'timer.app/reload
:port 9011}
serve {:port 3000})
identity)
Challenges I faced
Being a beginner in both boot-clj and Docker, I bumped into the following issues.
I couldn’t connect to nREPL running in Docker[2].
I got the following error when I used Cursive remote repl to connect.
Connecting to remote nREPL server...
Error connecting to localhost:9009 - class java.net.ConnectException: Connection refused
By going through document and looking at the source code[3], I found out that I need to run two tasks to have browser
repl working. The task cljs-repl
starts a repl server and the task start-repl
connects the repl server to browser.
The repl server listens to loopback interface[4] by default. I used the bind
nrepl option to override this setting
like the following:
cljs-repl {:nrepl-opts {:bind "0.0.0.0" :port 9009}}
Boot downloaded dependencies everytime I rebuilt docker images.
I used data container to store .m2
repositories. I just use the following command to rebuild and start the image:
docker-compose stop bootclj
docker-compose rm bootclj
docker-compose create bootclj
docker-compose start bootclj
Footnote:
3: boot_cljs_repl.clj and built_in.clj
4: https://clojure.org/reference/repl_and_main#_launching_a_socket_server