Как мне связаться с демоном docker изнутри контейнера с помощью сокетов Unix? - PullRequest
1 голос
/ 31 марта 2019

Немного предыстории, у меня есть приложение на основе docker-compose с несколькими сервисами. Каждый сервис может иметь n количество экземпляров. Моя стратегия межсервисного взаимодействия требует, чтобы служба redis знала о текущем состоянии приложения, с точки зрения того, когда добавляются новые экземпляры и когда экземпляры умирают или удаляются.

Из прочтения нескольких постов в блоге и вопросов переполнения стека я знаю, что решение заключается в том, чтобы связываться с демоном хоста Docker путем привязки сокета Unix /var/run/docker.sock к сокету в контейнере, но я не могу получить какую-либо поддержку , Большинство ресурсов, с которыми я сталкивался, дают довольно поверхностное объяснение того, что происходит, и определенно отсутствует какое-либо руководство по ELI5.

В настоящее время, в моем docker-compose.yml, у меня есть следующий конфиг как часть одного из моих сервисов на базе nodejs (нет, это не часть сервиса redis, т.к. я сейчас на стадии проверки концепции) ) ...

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

Я видел этот точный фрагмент десятки раз в других постах и ​​переполнял вопросы, но объяснения на этом обычно заканчиваются.

В моем сервисе nodejs / express у меня есть конечная точка, которую я создал для проверки, работает ли моя установка или нет. Он использует 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'
}

1 Ответ

2 голосов
/ 31 марта 2019

API-интерфейс демона Docker может быть связан с использованием конечных точек 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

Чтобы решить эту проблему, вы должны запросить действительную конечную точку API Docker Engine (документация для v1.39 ) в качестве пути HTTP. Пример списка контейнеров:

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

Если у вас под рукой curl, вы можете проверить это из вашей оболочки:

$ curl --unix-socket /var/run/docker.sock http://containers/json
...