英文:
Why can't an app inside a docker container access it's own API endpoint?
问题
我在Windows上使用Docker桌面应用程序。在Ubuntu WSL2中,我有一个运行着Meteor / Node.js服务器的Docker容器。从WSL内部使用docker-compose启动。
docker-compose.yaml
...
environment:
- ROOT_URL=http://localhost:8080
- PORT=8080
ports:
- "8080:8080"
在服务器上调用Meteor-Files,它将处理请求:
return new Promise((resolve, reject) => {
UserFiles.load(url, options,
(loadError, fileRef) => {
if (loadError) {
return reject(loadError);
} else {
return resolve(fileRef);
}
}, true);
});
现在,Docker容器内的应用程序必须访问自身的HTTP端点,如 http://127.0.0.1:8080/api
当我从容器外部调用此端点时,我得到了正确的结果。
当我通过终端连接到Docker容器并使用curl访问该端点时,我也得到了正确的结果。
更新:当在真实的Linux机器上运行Docker而不是Windows上的WSL2 Ubuntu时,它也可以工作。
但是,当运行在容器内的应用程序/服务尝试通过相同的端点和相同的URL调用自身时,我会收到 ECONNREFUSED - CONNECTION REFUSED
错误。
完整错误消息:
FetchError: request to http://127.0.0.1:8080/api failed, reason: connect ECONNREFUSED 127.0.0.1:8080
at ClientRequest.<anonymous> (/app/bundle/programs/server/npm/node_modules/meteor/fetch/node_modules/node-fetch/lib/index.js:1444:11)
at ClientRequest.emit (events.js:315:20)
at ClientRequest.EventEmitter.emit (domain.js:483:12)
at Socket.socketErrorListener (_http_client.js:426:9)
at Socket.emit (events.js:315:20)
at Socket.EventEmitter.emit (domain.js:483:12)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
=> awaited here:
at Function.Promise.await (/app/bundle/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:56:12)
at imports/startup/filemigration.js:273:20
at /app/bundle/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40 {
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED'
}
这可能是什么问题?也许是WSL2的安全性问题?
英文:
I use the docker desktop app on Windows.
Inside a Ubuntu WSL2 I have a docker container with a meteor / nodejs server running.
Started via docker-compose from inside the WSL.
docker-compose.yaml
...
environment:
- ROOT_URL=http://localhost:8080
- PORT=8080
ports:
- "8080:8080"
Call to Meteor-Files on the server, which will do the request:
return new Promise((resolve, reject) => {
UserFiles.load(url, options,
(loadError, fileRef) => {
if (loadError) {
return reject(loadError);
} else {
return resolve(fileRef);
}
}, true);
});
}
Now the app inside the docker container must access an HTTP endpoint of itself like http://127.0.0.1:8080/api
When I call the this endpoint from outside the docker, I get the correct result.
When I connect into the docker container with a terminal and curl the endpoint, I get the correct result.
Update: Also when running a Docker on a real Linux machine and not the WSL2 Ubuntu from Windows, it's working.
But, when the running app / service running inside the container tries to call itself by the same endpoint with the same URL, I get a ECONNREFUSED - CONNECTION REFUSED
error.
Full Error Message:
FetchError: request to http://127.0.0.1:8080/api failed, reason: connect ECONNREFUSED 127.0.0.1:8080
at ClientRequest.<anonymous> (/app/bundle/programs/server/npm/node_modules/meteor/fetch/node_modules/node-fetch/lib/index.js:1444:11)
at ClientRequest.emit (events.js:315:20)
at ClientRequest.EventEmitter.emit (domain.js:483:12)
at Socket.socketErrorListener (_http_client.js:426:9)
at Socket.emit (events.js:315:20)
at Socket.EventEmitter.emit (domain.js:483:12)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
=> awaited here:
at Function.Promise.await (/app/bundle/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:56:12)
at imports/startup/filemigration.js:273:20
at /app/bundle/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/fiber_pool.js:43:40 {
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED'
}
What could be the problem of this? Maybe a WSL2 security problem?
答案1
得分: 1
从错误消息来看,最终需要访问应用程序本身的HTTP端点的代码位于名为imports/startup/filemigration.js
的文件中。
从其名称来看,我假设它在应用程序启动时运行。但是,Meteor应用程序可能还没有启动其http
Node服务器,因此出现了“连接被拒绝”的错误消息。
甚至可能存在不同启动任务之间的竞争条件,这会导致在不同的环境下出现不同的行为。
如果可行的话,您可以尝试稍微延迟启动/迁移任务,以确保Meteor应用程序已经正确启动其服务器并侦听端口。
通常,您可以使用Meteor.startup(func)
来实现:
> 当客户端或服务器启动时运行[func]代码。
>
> [...]
>
> 在服务器上,该函数将在服务器进程完成启动时立即运行。
英文:
From the error message, the code that ultimately needs to access an HTTP endpoint of the app itself, resides in a file called: imports/startup/filemigration.js
From its name, I assume it runs when the app starts. However, there is a possibility that the Meteor app has not started its http
Node server yet, hence the "connection refused" error message.
There may even be a race condition between the different starting tasks, leading to different behaviors depending on the exact environments.
You can try delaying your startup / migration task a bit, if feasible, to ensure the Meteor app has correctly started its server and listens on the port.
You can typically use Meteor.startup(func)
for that:
> Run [func] code when a client or a server starts.
>
> [...]
>
> On a server, the function will run as soon as the server process is finished starting.
答案2
得分: 0
我不能确定任何事情,除非查看实际的代码或看到完整的错误消息,但尝试将您的以下部分替换:
- ROOT_URL=http://localhost:8080
替换为:
- ROOT_URL=http://127.0.0.1:8080
如果您在其他地方也有本地主机URL,请进行替换。
英文:
I can't say anything for sure without looking at the actual code or seeing the full error message, but try to replace your
- ROOT_URL=http://localhost:8080
with
- ROOT_URL=http://127.0.0.1:8080
And if you have any other places with localhost url, replace them as well.
答案3
得分: -1
我也不能确定地说什么,没有查看代码或错误的情况下,但您尝试将localhost
替换为Compose文件中容器的名称了吗?
英文:
I also can't say anything certainly without looking at the code or error, but have you tried replacing the localhost
with the name of the container within the compose file?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论