About /var/run/docker.sock

TL;DR

You have probably already run containers from the Docker Hub and noticed that some of them need to bind mount the /var/run/docker.sock file. What is this file and why it is sometimes used by containers? Short answer: it’s the unix socket the Docker daemon listens on by default and it can be used to communicate with the daemon from within a container.

Image modified from http://blog.honeybadger.io

Example

Let’s consider Portainer, an open source management interface used to manage a Docker host or a Swarm cluster. If used to manage the local Docker host Portainer can be ran with the following command, bind mounting the host’s docker’s unix socket.

docker container run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer

The interface is then available on port 9000 and allows to manage containers, images, volumes, …

To do all those management actions, Portainer communicates with the local Docker daemon through the /var/run/docker.sock file that it has access to via the bind mount.

Docker daemon API

When Docker platform is installed on a host, the Docker daemon listens on the /var/run/docker.sock unix socket by default. This can be seen from the options provided to the daemon, it should contain the following entry:

-H unix:///var/run/docker.sock

Note: additional -H options can be provided to the daemon so it also listens on tcp host/port or on other unix sockets.

All the HTTP endpoints defined in the Docker engine API v1.27 (last version to date), can thus be consumed through this unix socket.

Container creation

Using the Portainer UI, we can easily run containers. Behind the hood, HTTP requests are sent to the Docker daemon through the docker.sock. Let’s illustrate this and create a nginx container using curl.

Note: when using the HTTP API, 2 steps are necessary to run a container: it needs to be created first and then it can be started.

Create a nginx container

The following command uses curl to send the {“Image”:”nginx”} payload to the /containers/create endpoint of the Docker daemon through the unix socket. This will create a container based on Nginx and return its ID.

$ curl -XPOST --unix-socket /var/run/docker.sock -d ‘{“Image”:”nginx”}’ -H ‘Content-Type: application/json’ http://localhost/containers/create
{“Id”:”fcb65c6147efb862d5ea3a2ef20e793c52f0fafa3eb04e4292cb4784c5777d65",”Warnings”:null}

Start the container

Using the ID provided above, we can target the /containers/<ID>/start endpoint to start the newly created container.

$ curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/fcb6...7d65/start

We can now verify the nginx container is up and running

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fcb65c6147ef nginx “nginx -g ‘daemon …” 5 minutes ago Up 5 seconds 80/tcp, 443/tcp ecstatic_kirch
...

This illustrates how containers can easily be created behind the hood from within a container using the Docker socket. Obviously, a container will not be created using curl but you get the idea.

Streaming events from the Docker daemon

The Docker API also exposes the /events endpoint that can be used to get a stream of all the events the daemon generates. For instance, this can be used by a load balancer to get the creation/removal events of containers so it can dynamically update its configuration.

Let’s run a simple container and check how we can use Docker daemon events.

Running an alpine container

The following command run an alpine container in interactive mode and bind mount the docker.sock

$ docker run -v /var/run/docker.sock:/var/run/docker.sock -ti alpine sh

Listen events from the Docker daemon

From within the alpine container we then send a HTTP request to the /events endpoint through the Docker socket. The command hangs on waiting for new events from the daemon. When events will be generated, they will be streamed from the daemon.

curl --unix-socket /var/run/docker.sock http://localhost/events

Observe events

We then create a new container based on the nginx image, and we watch, through the alpine container standard output, the events generated by the Docker daemon.

docker container run -p 8080:80 -d nginx

We can observe that several events are received by the previous request.

Basically, 3 events occurred:

  • creation of the container
  • connection to the default bridge network
  • start of the container

Summary

I hope this quick explanation gives you a better understanding of the /var/run/docker.sock file and how it can be used when bind mounted in a container. Obviously, applications using this socket will not use curl but will go for dedicated libraries to send HTTP requests to the daemon.

Note: bind mounting the Docker daemon socket gives a lot of power to a container as it can control the daemon. It must be used with cautious, and only with containers we can trust.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.