【问题标题】:How can I POSTto the Docker API using node.js http?如何使用 node.js http POST 到 Docker API?
【发布时间】:2022-01-24 21:41:30
【问题描述】:

我创建了一个 node.js express 应用程序,它在 unix 套接字 /var/run/docker.sock 上调用 Docker API

任何涉及 GET 请求的操作都按预期工作。对于任何涉及 POST 请求的操作,都会执行该操作,但是以后从我的应用程序到 Docker API 的任何请求都会以 404 page not found 来回答。

例如,当我发送启动容器的请求时,容器将成功启动,但之后发送到 Docker API 的所有内容都会出现 404 错误。

在应用程序之外发出的请求(如使用 curl)继续有效,所以我确定我的代码有问题。

这是我怀疑导致问题的代码:

app.get('/containers/:containerId/start', (req, res) => {
  let containerId = req.params['containerId'];
  let apiOptions = requestOptions;
  apiOptions.path = `/containers/${containerId}/start`;
  apiOptions.method = 'POST';
  apiOptions.headers = {
    'Content-Type': 'application/json',
    'Content-Length': 0
  };
  let data = '';
  const apiReq = http.request(apiOptions, (apiRes) => {
    console.log(`${apiRes.statusCode} - ${apiOptions.path}`);
    apiRes.on('data', d => {
      data += d.toString();
    });
    apiRes.on('end', () => {
      res.setHeader("Content-Type", "application/json");
      res.send(JSON.stringify(data, null, 2));
    });
  });
  apiReq.on('error', err => {
    console.error(err)
  });
  apiReq.end();
});

它非常接近教科书示例,并且我有类似的代码可以毫无问题地执行 GET 请求。我没有在 POST 中使用 apiReq.write(data),因为 Docker API 期望正文为空。

我怀疑有什么东西在等待关闭连接,而我错过了可以执行此操作的代码行。

以下是各种 API 请求的响应代码的一些日志记录示例,以及导致应用挂起的发布请求的额外日志记录信息:

Listening on 0.0.0.0:8088.
200 - /images/json
200 - /containers/json?all="true"
{
  "socketPath": "/var/run/docker.sock",
  "path": "/containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start",
  "method": "POST",
  "headers": {
    "Content-Type": "application/json",
    "Content-Length": 0
  }
}
204 - /containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start
404 - /containers/json?all="true"
404 - /images/json

POST 的 204 响应根据API Doc 表示成功,我可以看到容器已启动。但该应用程序永远不会恢复。我必须杀死它并重新启动。

知道我缺少什么导致我的应用挂在 POST 请求上吗?

编辑:

我用一个简单的 30 秒 setInterval() 循环将调用 Docker API 的代码隔离在一个单独的程序中。有趣的是,它运行良好。我可以停止容器(在命令行上使用docker stop),并且循环中的 POST 请求再次成功启动它。

这是我正在测试的代码:

const http = require('http');

var containerId = '75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297';
var options = {
  socketPath: '/var/run/docker.sock',
  path: `/containers/${containerId}/start`,
  method: 'POST'
};

setInterval(() => {
  let data = '';
  const apiReq = http.request(options, (apiRes) => {
    apiRes.on('data', d => {
      data += d.toString();
    });
    apiRes.on('end', () => {
      console.log(`${apiRes.statusCode} - ${options.path}`);
      console.log(JSON.stringify(data, null, 2));
    });
  });
  apiReq.on('error', err => {
    console.error(err)
  });
  apiReq.end();
}, 30000);

这是 console.log() 输出:

204 - /containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start
""
304 - /containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start
""
304 - /containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start
""
204 - /containers/75b4ebdb7879e9cc9af134f63b4a02b2a218f52376fa377d89f5e384fdf78297/start
""

204 响应表明 API 已成功启动容器。 304 响应表明 API 无需执行任何操作,因为容器已经在运行。

简而言之,API 调用在我包含原始代码的 express.js 路由之外运行良好。我现在怀疑我的问题在于我的配置方式。

【问题讨论】:

    标签: node.js docker-api


    【解决方案1】:

    我想通了。问题在于这段代码:

      let apiOptions = requestOptions;
      apiOptions.path = `/containers/${containerId}/start`;
      apiOptions.method = 'POST';
      apiOptions.headers = {
        'Content-Type': 'application/json',
        'Content-Length': 0
      };
    

    之前,我在程序顶部声明了 requestOptions,如下所示:

    var requestOptions = {
      socketPath: '/var/run/docker.sock'
    };
    

    这是我的错误。我错误地认为let apiOptions = requestOptions 正在制作requestOptions 的副本。我现在相信它正在创建 apiOptions 作为 requestOptions 的指针。

    所以,当我做apiOptions.method = 'POST'时,它不仅影响了apiOptions,还影响了原来的requestOptions。

    我在 GET API 调用中使用了类似的逻辑,并且由于 GET 是默认方法,因此我从未在这些 API 请求中执行过 `apiOptions.method = 'GET'。

    把所有东西放在一起,我相信一旦我发出 POST 请求,requestOptions.method 就永远被困为“POST”。所以任何使用 POST 方法的 GET 请求自然会失败。

    以下是有效的:

    const dockerSocket = '/var/run/docker.sock';
    

    在程序的顶部,而不是

    var requestOptions = {
      socketPath: '/var/run/docker.sock'
    };
    

    还有,

      let apiOptions = {
        socketPath: dockerSocket,
        method: 'POST',
        path: `/containers/${containerId}/start`
      };
    

    在对 API 的调用中。

    【讨论】:

      猜你喜欢
      • 2023-04-01
      • 2021-05-30
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 2022-10-08
      • 2013-11-17
      • 2020-04-12
      • 1970-01-01
      相关资源
      最近更新 更多