DEV Community

smac89
smac89

Posted on • Edited on

cURL docker through sockets

Did you know that the docker daemon exposes a gRPC api for communication OR that cURL can send data to unix sockets?

Let's see how this all works.

Docker engine

The underlying infrastructure of the docker ecosystem is the docker engine.

It is implemented using a client/server model (much like most unix tools are), and exposes its API over a gRPC interface. As usual in such model, there is usually only one server, and many clients, and the story is no different for docker.

Docker architecture image
Docker architecture. Image from https://docs.docker.com

The daemon acts as the server, while the CLI which we are all familiar with acts as one of the clients. The single point of communication is usually exposed as a unix socket, and communication is carried out via gRPC exchanging data in the form of protocol buffers.

cURL --unix-socket

It turns out that cURL is not just great for talking to HTTP servers, but it can apparently also do the same via UNIX SOCKETS.

Let's say we wanted to get the docker version currently installed; Normally you would do the following on the command line:

docker version
Enter fullscreen mode Exit fullscreen mode

Using the api, we do something like

curl --silent --unix-socket /run/user/1000/docker.sock http://v1.41/version
Enter fullscreen mode Exit fullscreen mode

Note the above socket path assumes you are running docker in rootless mode and your user id is 1000. If running docker as root, the socket is likely to be located at /var/run/docker.sock

Which gives us:

{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"20.10.12","Details":{"ApiVersion":"1.41","Arch":"amd64","BuildTime":"2021-12-13T11:46:12.000000000+00:00","Experimental":"false","GitCommit":"459d0df","GoVersion":"go1.16.12","KernelVersion":"5.13.0-28-generic","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"containerd","Version":"v1.4.12","Details":{"GitCommit":"7b11cfaabd73bb80907dd23182b9347b4245eb5d"}},{"Name":"runc","Version":"1.0.2","Details":{"GitCommit":"v1.0.2-0-g52b36a2d"}},{"Name":"docker-init","Version":"0.19.0","Details":{"GitCommit":"de40ad0"}}],"Version":"20.10.12","ApiVersion":"1.41","MinAPIVersion":"1.12","GitCommit":"459d0df","GoVersion":"go1.16.12","Os":"linux","Arch":"amd64","KernelVersion":"5.13.0-28-generic","BuildTime":"2021-12-13T11:46:12.000000000+00:00"}
Enter fullscreen mode Exit fullscreen mode

How cool is that?!

You can take this even a step further, and expose a local docker daemon, over tcp to your friends over the internet. Here is a quick example which doesn't use cURL, but rather uses ncat:

server

ncat -kl -p 2376 -c 'ncat -U /run/user/1000/docker.sock'
Enter fullscreen mode Exit fullscreen mode

client

curl http://localhost:2376/version | jq
Enter fullscreen mode Exit fullscreen mode

One last thing to mention is that the format of the url ex. http://v1.41/version is not strict. Any of the following would have given the same result:

  • http:/foo/version
  • http://dummy/version
  • http:/./version

The recommendation is to use the version of the API supported by docker as the first part of the url, then the actual commands come later.


Sources:

Top comments (0)