Table of Contents
This post is a reminder for either myself or other people wanting to use Common Lisp applications in Docker containers.
The end goal
At the end of this post, there will be:
- 2 Docker containers: web and postgres
- The
db
container will run a postgresql instance - The
web
container will run a Hunchentoot web server - The
web
container will run a swank server
The 2 last points mean that:
- Going to http://localhost:4242 will hit Hunchentoot
- Running
M-x slime-connect 127.0.0.1 5555
will connect to the container’s swank server
The required Lisp code
To have a Hunchentoot instance as well as a swank server, the following Lisp code is needed, somewhere in the application:
(defun main (&rest args)
(declare (ignore args))
(hunchentoot:start
(make-instance 'hunchentoot:easy-acceptor
:port 4242
:address "localhost"))
(setf swank::*loopback-interface* "0.0.0.0")
(swank-loader:init)
(swank:create-server :port 4005
:style swank:*communication-style*
:dont-close t))
Note that the swank server’s loopback interface must be
0.0.0.0
. This is required so that the host can connect to the
container. 127.0.0.1
wouldn’t work and building an ssh tunnel is
more complicated than it’s worth. This is not a security issue,
since the container will be on a network shared between the host and
the container only.
This code can be compiled to a binary using something similar to this:
$ buildapp --load-system foo --entry foo::main
The containers
Since 2 containers will be needed, their specification is needed.
- The
db
container will just be the officialpostgres
image with a persistent folder. (So that the data in the databases are persisted between each container’s restart.) - The
web
container will be based on a custom Docker image.
The db
container
Here is the command to create the db
container:
$ sudo docker run \
--volume=/var/lib/postgresql/data \
--env="POSTGRES_PASSWORD=password" \
--name=db postgres
This will create a container named db
, based on the postgres
image. The image will be downloaded from dockerhub if you don’t have
it locally. The POSTGRES_PASSWORD
environment variable allows you to
define the password for the postgres
database, usable by the
postgres
user in the container.
To start and stop the container later on, the following commands can be used:
$ sudo docker start db
$ sudo docker stop db
As simple as that!
The web
container
This container needs a special image. For that, a Dockerfile
is
needed. Before this, a simple Makefile
should be used to simplify
life.
Here is a sample Makefile
(let’s assume the project name is foo
):
all:
buildapp --load-system foo --entry foo::main --output foo.bin
With this done, here is a sample Dockerfile
:
# This image is available on dockerhub, automatically downloaded
FROM dparnell/sbcl-1.2.5
# 4242 is for hunchentoot, 4005 is for swank
EXPOSE 4242 4005
# Going to this folder means ASDF automatically picks up the project
WORKDIR /root/common-lisp/foo
# The command to run every time the container is started
CMD make && ./foo.bin
To build this custom image:
$ sudo docker build -t my/foo .
Now that the custom image (named my/foo
) is ready, let’s create a
container:
$ sudo docker run \
--volume="$PWD:/root/common-lisp/foo
--link="db:dbhost"
--publish="4242:4242"
--publish="5555:4005"
--name="web"
my/foo
Here is what each argument means:
- The
--volume
argument defines a folder mapping between the host and the container. - The
--link
argument adds a link between 2 containers. Here, thedb
container’s IP will be added to theweb
container’s/etc/hosts
, under the namedbhost
. This will let you connect to the database using the following parameters:- username:
postgres
- password:
password
- database:
postgres
- host:
dbhost
- username:
- The
--publish
argument defines a port forwarding between the host and the container. In this case,host:4242
forwards tocontainer:4242
, andhost:5555
forwards tocontainer:4005
. - The
--name
argument gives a name to the container. - The last argument is the image that the container is based on.
Same as earlier, to start/stop the container:
$ sudo docker start web
$ sudo docker stop web
Conclusion
So, there it is. There now is 2 containers, and they:
- Run a postgresql instance
- Run a hunchentoot instance
- Run a swank-server instance
Which means:
- You can go on http://localhost:4242
- You can
M-x slime-connect
on127.0.0.1:5555