如何使用 unix 套接字从容器内部与 docker 守护程序通信?

How do I communicate with the docker daemon from inside a container using unix sockets?

一些背景知识,我有一个基于 docker-compose 的具有多个服务的应用程序。每个服务可能有 n 个实例。我的服务间通信策略要求 Redis 服务了解应用程序的当前状态,包括何时添加新实例以及何时死亡或删除实例。

通过阅读多篇博客文章和堆栈溢出问题,我知道解决方案涉及通过将 unix 套接字 /var/run/docker.sock 绑定到容器中的套接字来与主机 docker 守护进程通信,但我无法获得任何牵引力。我遇到的大多数资源都对正在发生的事情给出了相当浅显的解释,而且那里肯定缺乏任何类型的 ELI5 教程。

目前,在我的 docker-compose.yml 中,我有以下配置作为我基于 nodejs 的服务之一的一部分(不,它不是 redis 服务的一部分 b/c 我只是在证明目前处于概念阶段)...

volumes:
  - /var/run/docker.sock:/var/run/docker.sock:ro

我已经在其他帖子和堆栈溢出问题中多次看到这个确切的片段,但解释通常到此为止。

在我的 nodejs/express 服务中,我创建了一个端点,用于测试我的设置是否有效。它使用 Sindre Sorhus 的 got 因为它能够使用 unix 套接字。

app.get('/dockersocket', async (req, res) => {
  const data = await got('unix:/var/run/docker.sock:/var/run/docker.sock')
  res.status(200).json({ data: data })
})

不用说,它在当前形式下不起作用。当我将上面的代码片段包装在 try/catch 和 console.log 错误中时,我收到以下输出...

{
  HTTPError: Response code 404(Not Found)
  at EventEmitter.emitter.on(/usr/src / app / node_modules / got / source / as - promise.js: 74: 19)
  at processTicksAndRejections(internal / process / next_tick.js: 81: 5)
  name: 'HTTPError',
  host: null,
  hostname: 'unix',
  method: 'GET',
  path: '/var/run/docker.sock',
  socketPath: '/var/run/docker.sock',
  protocol: 'http:',
  url: 'http://unix/var/run/docker.sock:/var/run/docker.sock',
  gotOptions: {
    path: '/var/run/docker.sock',
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: null,
    port: null,
    hostname: 'unix',
    hash: null,
    search: null,
    query: null,
    pathname: '/var/run/docker.sock:/var/run/docker.sock',
    href: 'http://unix/var/run/docker.sock:/var/run/docker.sock',
    retry: {
      retries: [Function],
      methods: [Set],
      statusCodes: [Set],
      errorCodes: [Set]
    },
    headers: {
      'user-agent': 'got/9.6.0 (https://github.com/sindresorhus/got)',
      'accept-encoding': 'gzip, deflate'
    },
    hooks: {
      beforeRequest: [],
      beforeRedirect: [],
      beforeRetry: [],
      afterResponse: [],
      beforeError: [],
      init: []
    },
    decompress: true,
    throwHttpErrors: true,
    followRedirect: true,
    stream: false,
    form: false,
    json: false,
    cache: false,
    useElectronNet: false,
    socketPath: '/var/run/docker.sock',
    method: 'GET'
  },
  statusCode: 404,
  statusMessage: 'Not Found',
  headers: {
    'content-type': 'application/json',
    date: 'Sun, 31 Mar 2019 01:10:06 GMT',
    'content-length': '29',
    connection: 'close'
  },
  body: '{"message":"page not found"}\n'
}

Docker 守护程序 API 可以使用 HTTP 端点进行通信,默认情况下侦听 UNIX 套接字。这意味着您可以像任何普通的 HTTP 服务器一样与它通信,当它是一个套接字时只需一些额外的处理。

您收到一个错误,因为当您向套接字发送请求时,您请求的路径错误。请求的语法是:

PROTOCOL://unix:SOCKET_PATH:ENDPOINT_PATH

对于您的代码,这意味着:

const data = await got('unix:/var/run/docker.sock:/var/run/docker.sock')

// protocol      = http (default by library)
// socket path   = /var/run/docker.sock
// endpoint path = /var/run/docker.sock

要解决您的问题,您应该请求一个有效的 Docker 引擎 API 端点 (documentation for v1.39) 作为 HTTP 路径。列出容器的示例:

await got('unix:/var/run/docker.sock:/containers/json')

如果您有 curl 方便,您可以从 shell:

进行测试
$ curl --unix-socket /var/run/docker.sock http://containers/json