DEV Community

Cover image for Running docker commands from Common Lisp REPLs
Rajasegar Chandran
Rajasegar Chandran

Posted on

Running docker commands from Common Lisp REPLs

In this post, we are going to take a look at how we can run docker commands from Common Lisp. Lately I have been exploring Common Lisp development in Docker. So I have to run docker commands from a terminal frequently.

I was basically looking for a way to run docker commands within SLIME itself. Then I came across the uiop:run-program function from the Common Lisp Cookbook

uiop:run-program fully portably runs a program as a synchronous external subprocess.

So if you want to list all the Docker containers from SLIME or any Lisp REPL, you have to call the run-program function like this:

(uiop:run-program "docker ps -a" :output t)
Enter fullscreen mode Exit fullscreen mode

We need to provide the :output t argument to print the results of the command to the standard output.

The result will be something like:

CL-USER> (uiop:run-program "docker ps -a" :output t)
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS                  PORTS     NAMES
673b20976166   docker101tutorial   "/docker-entrypoint.…"   19 months ago   Exited (0) 4 days ago             docker-tutorial
NIL
NIL
0
Enter fullscreen mode Exit fullscreen mode

cl-docker

Running docker commands everytime using uiop:run-program and passing all the options to print the output to the standard output felt like a time-consuming and non-Lispy way of doing stuff for me.

I wanted to run docker commands in a more natural way using Lisp, so I planned to write a package for the same. The original inspiration for this idea came from another Common Lisp package called cl-virtualbox by Fernando Borretti. cl-virtualbox is a library that allows you to control VirtualBox from Common Lisp, by calling the vboxmanage command.

So our new package called cl-docker will allow us to control Docker from Common Lisp by calling the docker command.

Image description

Installation

(ql:quickload :cl-docker)
Enter fullscreen mode Exit fullscreen mode

Usage

So now, to list out all the Docker containers in your machine, you can just call the below function in your REPL

;; List all docker containers
(docker:ps :a)
Enter fullscreen mode Exit fullscreen mode

Output:

"CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS                    PORTS     NAMES
673b20976166   docker101tutorial   \"/docker-entrypoint.…\"   19 months ago   Exited (0) 16 hours ago             docker-tutorial
"
NIL
0
Enter fullscreen mode Exit fullscreen mode

Following is some of the docker commands and their corresponding cl-docker functions

docker command cl-docker
docker ps -a (docker:ps :a)
docker images (docker:images)
docker build DIRECTORY (docker:build "myimage")
docker rm CONTAINER (docker:rm "web")
docker start CONTAINER (docker:start "web")
docker stop CONTAINER (docker:stop "web")

The more complete list of commands can be viewed from the project README

Moving away from uiop:run-program

Using uiop:run-program to run and manage docker from Common Lisp seems like an easy way to get things done. But it's not a clean and scalable way of doing things, basically we are interfacing with docker using the operating system command line capabilities. There are still issues in capturing the proper output, error information and unnecessary output like NIL and 0, which are actually the function return values and the return codes for the commands you run with uiop:run-program.

So how do we get around these things? The best way to properly manage docker from Common Lisp is to use the Docker Engine SDKs.

Docker provides an API for interacting with the Docker daemon (called the Docker Engine API), as well as SDKs for Go and Python. At present, there is no pre-built SDK available for Common Lisp.

The SDKs allow you to build and scale Docker apps and solutions quickly and easily. So for Common Lisp, we have to use the Docker Engine API directly.

The Docker Engine API is a RESTful API accessed by an HTTP client such as wget or curl, or the HTTP library which is part of most modern programming languages.

Using the SDK API to get a list of containers, just like using docker ps, we need to send a curl request like this:

curl --unix-socket /var/run/docker.sock http://localhost/v1.41/containers/json
Enter fullscreen mode Exit fullscreen mode

All we need to figure out is how to replicate this curl request in Common Lisp using an HTTP Client library using unix sockets. That's what I am trying to figure out now. If you have any ideas, please let me know in the comments.

cl-docker is still in early stages of development. It may not have covered all the docker commands with all the options that can be provided. So please give a try to the package and let me know for any queries/feedback in the comments section. You can also raise bug fixes, enhancements and feature requests through the Github issues

Top comments (2)

Collapse
 
dnd profile image
dnd

For sending http or https client requests you can use drakma or zaserve (available thru quicklisp).

(drakma:http-request ...) or (net.aserve.client:do-http-request ...)

Collapse
 
dnd profile image
dnd

And if their API is working through JSON format, which it likely is, then you can try cl-json or yason for the json encoding/decoding.