无法连接Docker容器中的Go服务器

5
我正在尝试在Docker容器中运行用Golang编写的HTTP服务器,但我一直收到连接被拒绝的错误。所有内容都在Ubuntu 20.04服务器虚拟机内运行,在我的Windows 10机器上运行。
Go服务器代码如下:
package main

import "github.com/lkelly93/scheduler/internal/server"

func main() {
    server := server.NewHTTPServer()
    server.Start(3000)
}

package server

import (
    "context"
    "fmt"
    "net/http"
)

type HTTPServer interface {
    Start(port int) error

    Stop() error
}

func NewHTTPServer() HTTPServer {
    return &httpServer{}
}

type httpServer struct {
    server *http.Server
}

func (server *httpServer) Start(port int) error {
    serveMux := newServeMux()
    server.server = &http.Server {
        Addr: fmt.Sprintf(":%d", port),
        Handler: serveMux,
    }
    return server.server.ListenAndServe()
}

func (server *httpServer) Stop() error {
    return server.server.Shutdown(context.Background())
}

我的Dockerfile:
FROM ubuntu:20.04

RUN apt-get update -y

#Install needed packages
RUN apt-get install software-properties-common -y
RUN apt-get install python3 -y
RUN apt-get update -y 
RUN apt-get install python3-pip -y
RUN apt-get install default-jre -y

#Install language dependacies
    #Python
    RUN pip3 install numpy

#Reduce VM size
# RUN rm -rf /var/lib/apt/lists/*

#Setup working DIRs
RUN mkdir secure
RUN mkdir secure/runner_files

COPY scheduler /secure
WORKDIR /secure

EXPOSE 3000

CMD ["./scheduler"] <-- The go server is compiled into a binary called scheduler

我构建给定的Dockerfile,然后运行:
docker run -d --name scheduler -p 3000:3000 scheduler:latest

然后我用以下代码获取容器的地址:

docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' scheduler
->172.17.0.2

最后我使用 cURL 发送了一个 http 请求:
curl http://172.17.0.2:3000/execute/python --data '{"Code":"print(\"Hello\")"}'

我正在获取

curl: (7) Failed to connect to 172.17.0.2 port 3000: Connection refused

但应该得到
{"Stdout":"Hello\n"}%

如果我在Ubuntu虚拟机上运行Go服务器,从我的Win10机器上调用它没有任何问题,但是当它存在于Docker容器中时,似乎无法从Ubuntu机器上调用Go服务器。
Go代码比这更复杂,但在此处发布所有内容太多了,请随意查看整个repo https://github.com/lkelly93/scheduler
最终它将成为我想要创建的网站的后端,该网站可以运行代码。类似于LeetCode或Repl.it。
谢谢!
编辑:
docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
2a56a973040f        scheduler:latest    "./scheduler"       37 seconds ago      Up 36 seconds       0.0.0.0:3000->3000/tcp   scheduler

docker容器2a56a973040f的日志未输出。

编辑2:

docker run -it --net container:2a56a973040f nicolaka/netshoot ss -lnt
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      4096               *:3000            *:*

编辑3:

阅读手册后,我发现如果在我的镜像中添加标签--network=host,然后运行。

curl http://localhost:3000/execute/python --data '{"Code":"print(\"Hello\")"}'

我获得了正确的输出。虽然这有效,但我希望能够同时运行多个docker镜像。因此,我更喜欢使用IP地址来寻址它们。所以我认为这不是一个永久的解决办法。

Docker 说你的服务器在 172.17.0.2 上,但你似乎正在使用 curl 访问 172.17.0.1。 - Burak Serdar
复制的命令有误,应该是172.17.0.2。我会更改它。 - Luke Kelly
也许这是一个服务器问题,而不是Docker问题。服务器日志输出了什么? - pygeek
1
你尝试过传统的本地主机(localhost)吗? - pygeek
@pygeek 我认为这不是服务器的问题,因为我在docker外运行时没有任何问题。 - Luke Kelly
3个回答

7
为了解决这个问题,我在我的服务器上将IP地址设置为0.0.0.0:4000。 我使用gin,所以示例看起来像这样:
r := gin.Default()
r.run("0.0.0.0:4000")

在此之后,我终于能够通过浏览器访问它了。


2
救星。谁知道我的问题竟然只是在于使用r.run("localhost:4000")。 - subash
我赞同这个观点……你应该得到一枚奖章! - John Harrington
r.run(:4000) 也可以工作。 - Eray

1
你已经发布了端口,该端口将从Docker主机转发到容器。因此,您想要连接到http://localhost:3000。由于Docker在虚拟机中运行且这些私有IP仅在虚拟机中可见,因此连接到容器IP可能会失败桌面安装。
如果您正在运行docker-machine(这是旧版docker工具箱的情况),则需要获取VM的IP地址。运行echo $DOCKER_HOST以查看IP地址,并将端口调整为3000端口。

我尝试了这个,但是出现了以下错误: curl: (56) 接收失败:连接被对等方重置 - Luke Kelly
@LukeKelly 不,这意味着你正在运行最近几年的 Docker 版本。 - BMitch
@LukeKelly 容器还在运行吗?在你的问题中包含 docker container ls -a。同时包括 docker container logs $id,其中 $id 是你的容器 ID。 - BMitch
谢谢你的帮助!我已经在上面添加了所请求的信息。 - Luke Kelly
已将更新的信息添加到上面的帖子中!再次感谢您的帮助! - Luke Kelly
显示剩余3条评论

0
在继续搜索后,我按照this指南创建了自己的"用户定义桥接网络"。如果我启动容器并将其连接到这个网络,它就能正常工作!不过,我希望有人能够解释其中的原因!

1
这听起来像是您正在从另一个容器而不是主机到发布的端口运行curl。对于这种情况,网络规则非常不同。 - BMitch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接