Docker From A Distance – The Remote API

by frankDecember 24, 2013

Docker-logoMany people use docker from the command line to build images, run containers and manage Docker on their machine. However, you can also run the same Docker commands via its remote REST API. In this blog I will guide you through Docker’s remote API using curl while pointing out a few details and tools that you might not know about. We will remotely search and pull an elasticsearch image, run a container and clean up after ourselves.

Docker’s Remote API

I assume you know how to build and run a Docker container via the command line. If not, check out Quinten’s blog post on how to create tomcat instances with Docker. When installing Docker the daemon is configured to listen on a UNIX socket. It’s fun to realize that we can access the REST API via the socket without any additional configuration. To list all images run the following command:

$ echo -e "GET /images/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 858
Connection: close
Date: Fri, 20 Dec 2013 16:02:41 GMT

[{"Repository":"ubuntu","Tag":"12.04","Id":"8dbd9e392...",
"Created":1365714795,"Size":131502179,"VirtualSize":131502179},
{"Repository":"ubuntu","Tag":"latest","Id":"8dbd9e392...",
"Created":1365714795,"Size":131502179,"VirtualSize":131502179},
{"Repository":"ubuntu","Tag":"precise","Id":"8dbd9e392...",
"Created":1365714795,"Size":131502179,"VirtualSize":131502179},
{"Repository":"ubuntu","Tag":"12.10","Id":"b750fe792...",
"Created":1364102658,"Size":24653,"VirtualSize":180116135},
{"Repository":"ubuntu","Tag":"quantal","Id":"b750fe792...",
"Created":1364102658,"Size":24653,"VirtualSize":180116135}]

You have to use netcat because you cannot echo to a socket from bash. For more information on communication with UNIX sockets in this way, see this Gist which has more code samples and useful links.

Listening on a port

To get Docker to listen on a port first stop docker.

$ sudo service docker stop

Now edit Docker’s upstart file at /etc/init/docker.conf so it looks like this:

description     "Docker daemon"

start on filesystem and started lxc-net
stop on runlevel [!2345]

respawn

script
    /usr/bin/docker -H tcp://127.0.0.1:4243 -d
end script

Now run

$ sudo service docker start

and Docker is listening on port 4243. However, note that this is insecure. Check out James Carr’s blog post on securing Docker’s remote API.

Example – Pulling, starting and stopping Elasticsearch

Let’s access the API with curl to see what is going on. We will run the following steps:

  • Search for an elasticsearch image in the Docker index
  • Pull an image from the Docker registry
  • Create the container
  • Start the container
  • Stop the container
  • Remove the container

Curious to know more about the Docker terminology like index and registry? Check this blog by Troy Howard.

Search

Let’s search for some elasticsearch images using the following call:

$ curl -s -XGET http://localhost:4243/images/search?term=elasticsearch | jq '.[] | .name'
"paulczar/elasticsearch"
"fgrehm/elasticsearch"
"orchardup/elasticsearch"
"mschoch/elasticsearch"
"bacongobbler/elasticsearch"
"mereghost/elasticsearch"
"quintenk/elasticsearch"
"coaxys/elasticsearch"
"ehazlett/elasticsearch"
...

Here I filter the results through jq, a great tool for processing JSON on the command line. It’s like sed for JSON.

Pull an image

Now let’s pull the vieux/elasticsearch image:

$ curl -XPOST http://localhost:4243/images/create?fromImage=vieux/elasticsearch
...
"progress":"[==================================================\u003e] 10.24 kB/10.24 kB 0","id":"daf68f48da59"}
{"status":"Download complete","progressDetail":{},"id":"daf68f48da59"}
{"status":"Download complete","progressDetail":{},"id":"daf68f48da59"}

Create a container

When running a container via the command line you would use the docker ‘run’ command. This is a composite command, consisting of the commands ‘create’ and ‘start’.
The remote API does not support the ‘run’ command. You have to execute ‘create’ and ‘start’ separately. To create a container run:

$ curl -X POST -H "Content-Type: application/json" http://localhost:4243/containers/create -d '{
     "Hostname":"",
     "User":"",
     "Memory":0,
     "MemorySwap":0,
     "AttachStdin":false,
     "AttachStdout":true,
     "AttachStderr":true,
     "PortSpecs":null,
     "Privileged": false,
     "Tty":false,
     "OpenStdin":false,
     "StdinOnce":false,
     "Env":null,
     "Dns":null,
     "Image":"vieux/elasticsearch",
     "Volumes":{},
     "VolumesFrom":"",
     "WorkingDir":""
}'
{"Id":"d1fa1b772481441228b93a26cc7c384a9a08cb79ea5516f101faa89564e9c752"}

Start a container

To start the container we reuse the ID we got from the ‘create’ command.

$ curl -XPOST http://localhost:4243/containers/398378dfa8a5409c4ad011e96788e085d2f13bb6dff07c5394a955609fcf7327/start

and we can see that elasticsearch is running!

$ curl -X GET http://localhost:9200
{
  "ok" : true,
  "status" : 200,
  "name" : "Banner, Robert Bruce",
  "version" : {
    "number" : "0.90.5",
    "build_hash" : "c8714e8e0620b62638f660f6144831792b9dedee",
    "build_timestamp" : "2013-09-17T12:50:20Z",
    "build_snapshot" : false,
    "lucene_version" : "4.4"
  },
  "tagline" : "You Know, for Search"
}
$ docker ps
CONTAINER ID        IMAGE                        COMMAND                CREATED             STATUS              PORTS               NAMES
398378dfa8a5        vieux/elasticsearch:0.90.1   /bin/sh -c elasticse   34 minutes ago      Up 6 seconds        9200/tcp            sharp_pasteur

Stop a container

And now let’s stop the container:

$ curl -X POST http://localhost:4243/containers/398378dfa8a5409c4ad011e96788e085d2f13bb6dff07c5394a955609fcf7327/stop
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Remove the container

Let’s clean up and remove the container:

$ docker ps -a | grep vieux
398378dfa8a5        vieux/elasticsearch:0.90.1    /bin/sh -c elasticse   About an hour ago   Exit 137                                sharp_pasteur
$ curl -X DELETE http://localhost:4243/containers/398378dfa8a5409c4ad011e96788e085d2f13bb6dff07c5394a955609fcf7327
$ docker ps -a | grep vieux
$

The Docker phenomenon

Hope this post gave you a useful intro to Docker’s remote API. If you want to a more detailed description of the remote API check out the official Docker remote API documentation. Docker is becoming very popular. The community shares Dockerfiles, meetups pop up all over the planet and people keep pet whales and call them Moby Dock. Okay, maybe I am fibbing on that one. Point is, people like Docker because you can now do things that were impossible or very hard before. You could use a VMs instead but they can be cubersome and slow. Now you can encapsulate an entire application, including its code, configuration and environment and recreate and share it. Docker is actively developed and not production ready, but people see its potential and push its boundaries.

Feedback

Because of the potential we see in Docker we are interested in your feedback. How are you using Docker? What is your favourite use case? What are some downsides of Docker? If you had magic powers and you could….well if you had magic powers you wouldn’t use Docker you would just use your magic 😉 No but really, which feature would you like to see added to Docker and why? What do you think of our posts on Docker? Interesting, meh, or something else? Do you like to see more code, no code or good practices? Please let us know. We are looking forward hearing from you.

In closing I wish you happy holidays and a great new year!

P.S. Don’t forget to return your Docker configuration back to its original state.