DevOps Docker

Docker Tips : about /var/run/docker.sock

Communicate with the Docker daemon from within a container

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.

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.

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

Image for post

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 the 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.

Start the container

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

We can now verify the nginx container is up and running.

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 or 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 runs an Alpine container in interactive mode and bind mounts 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 first install the curl utility using the apk package manager.

# apk update && apk add curl

We can then send a HTTP request to the /events endpoint through the Docker socket. The command hangs on, waiting for new events from the daemon. Each new event will then 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.2

$ curl –unix-socket /var/run/docker.sock http://localhost/events
{
  “status”: “create”,
  “id”: “277786a066994b4d842dc097c4544e2ddcf50ffe0b6aa8352812ca0aadec4078”,
  “from”: “nginx”,
  “Type”: “container”,
  “Action”: “create”,
  “Actor”: {
    “ID”: “277786a066994b4d842dc097c4544e2ddcf50ffe0b6aa8352812ca0aadec4078”,
    “Attributes”: {
      “image”: “nginx”,
      “name”: “hardcore_carson”
    }
  },
  “time”: 1491683503,
  “timeNano”: 1491683503003280100
}
{
  “Type”: “network”,
  “Action”: “connect”,
  “Actor”: {
    “ID”: “18147ed9f4510d0149a0810916434df19b3d03f30e17ac4effcbcc1d2371ba97”,
    “Attributes”: {
      “container”: “277786a066994b4d842dc097c4544e2ddcf50ffe0b6aa8352812ca0aadec4078”,
      “name”: “bridge”,
      “type”: “bridge”
    }
  },
  “time”: 1491683503,
  “timeNano”: 1491683503061245700
}
{
  “status”: “start”,
  “id”: “277786a066994b4d842dc097c4544e2ddcf50ffe0b6aa8352812ca0aadec4078”,
  “from”: “nginx”,
  “Type”: “container”,
  “Action”: “start”,
  “Actor”: {
    “ID”: “277786a066994b4d842dc097c4544e2ddcf50ffe0b6aa8352812ca0aadec4078”,
    “Attributes”: {
      “image”: “nginx”,
      “name”: “hardcore_carson”
    }
  },
  “time”: 1491683503,
  “timeNano”: 1491683503389984300

}

Basically, three 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 caution, and only with containers we can trust.

Đăng ký liền tay Nhận Ngay Bài Mới

Subscribe ngay

Cám ơn bạn đã đăng ký !

Lỗi đăng ký !

Add Comment

Click here to post a comment

Đăng ký liền tay
Nhận Ngay Bài Mới

Subscribe ngay

Cám ơn bạn đã đăng ký !

Lỗi đăng ký !