【问题标题】:How do I communicate with the docker daemon from inside a container using unix sockets?如何使用 unix 套接字从容器内部与 docker 守护进程通信?
【发布时间】:2019-03-31 01:17:42
【问题描述】:

一点背景知识,我有一个基于 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

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

在我的 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 })
})

不用说,它不能以目前的形式工作。当我将上面的 sn-p 包装在 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'
}

【问题讨论】:

    标签: sockets docker docker-compose communication unix-socket


    【解决方案1】:

    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 Engine 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
    

    【讨论】:

    • 感谢您的解释和文档链接。我以前没有遇到过。我现在已经启动并运行它,但端点路径实际上应该是/containers/json 而不是/docker/containers/json。如果您想修改您的答案,我很乐意将其标记为已接受。
    • @J.Munson 注意并编辑,感谢您的更正。我很高兴听到它现在对你有用!
    • 我的下一个问题是……如何让 docker 引擎推送更新,而不是需要不断地轮询 docker 以了解应用程序的状态。有两个项目似乎解决了这个问题,nginx-proxytraefik,但我不知道他们是如何解决这个问题的。
    • 可能是SystemEvents 端点?您可以从中流式传输事件,并且可以使用 docker events 进行测试。
    猜你喜欢
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    • 2019-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    相关资源
    最近更新 更多