如何使用 node.js http 发布到 Docker API?
How can I POSTto the Docker API using node.js http?
我创建了一个 node.js express 应用程序,它在 unix 套接字 /var/run/docker.sock
上调用 Docker API
任何涉及 GET 请求的操作都按预期工作。对于任何涉及 POST 请求的操作,都会执行该操作,但随后从我的应用程序到 Docker API 的任何未来请求都会得到 404 页面未找到的答复。
例如,当我发送启动容器的请求时,容器会成功启动,但是发送到 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 请求的响应代码的一些日志记录示例,以及导致应用程序挂起的 post 请求的额外日志记录信息:
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 个请求上挂起吗?
编辑:
我已经将调用 Docker API 的代码隔离在一个单独的程序中,使用一个简单的 30 秒 setInterval() 循环。有趣的是,它运行良好。我可以停止容器(在命令行上使用 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 路由之外工作正常,我包含了原始代码。我现在怀疑我的问题出在我的配置方式上。
我明白了。问题在于这段代码:
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的调用中。
我创建了一个 node.js express 应用程序,它在 unix 套接字 /var/run/docker.sock
上调用 Docker API任何涉及 GET 请求的操作都按预期工作。对于任何涉及 POST 请求的操作,都会执行该操作,但随后从我的应用程序到 Docker API 的任何未来请求都会得到 404 页面未找到的答复。
例如,当我发送启动容器的请求时,容器会成功启动,但是发送到 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 请求的响应代码的一些日志记录示例,以及导致应用程序挂起的 post 请求的额外日志记录信息:
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 个请求上挂起吗?
编辑:
我已经将调用 Docker API 的代码隔离在一个单独的程序中,使用一个简单的 30 秒 setInterval() 循环。有趣的是,它运行良好。我可以停止容器(在命令行上使用 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 路由之外工作正常,我包含了原始代码。我现在怀疑我的问题出在我的配置方式上。
我明白了。问题在于这段代码:
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的调用中。