英文:
Cannot connect to Go GRPC server running in local Docker container
问题
我有一个Go gRPC服务。我在Mac Sierra上进行开发。当在本地运行gRPC客户端与服务进行通信时,一切正常。但是当在Docker容器中运行相同的客户端与相同的服务进行通信时,我会收到以下错误信息:
transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing
这是我的Docker文件:
FROM golang:1.7.5
RUN mkdir -p /go/src/github.com/foo/bar
WORKDIR /go/src/github.com/foo/bar
COPY . /go/src/github.com/foo/bar
# ONBUILD RUN go-wrapper download
RUN go install
ENTRYPOINT /go/bin/bar
EXPOSE 51672
构建镜像的命令:
docker build -t bar .
启动Docker容器的命令:
docker run -p 51672:51672 --name bar-container bar
其他信息:
-
在Docker容器内部运行的客户端程序正常工作。
-
连接到常规的REST端点正常工作(是否与HTTP2和gRPC相关?)。
-
在OS X上运行
lsof
命令会得到以下结果:$lsof -i | grep 51672 com.docke 984 oldDave 21u IPv4 0x72779547e3a32c89 0t0 TCP *:51672 (LISTEN) com.docke 984 oldDave 22u IPv6 0x72779547cc0fd161 0t0 TCP localhost:51672 (LISTEN)
这是我的服务器代码片段:
server := &Server{}
endpoint := "localhost:51672"
lis, err := net.Listen("tcp", endpoint)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterExpServiceServer(s, server)
// Register reflection service on gRPC server.
reflection.Register(s)
log.Info("Starting Exp server: ", endpoint)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
英文:
I have a go grpc service. I'm developing on a mac, sierra. When running a grpc client against the service locally, all is well, but when running same client against same service in the docker container I get this error:
transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing
this is my docker file:
FROM golang:1.7.5
RUN mkdir -p /go/src/github.com/foo/bar
WORKDIR /go/src/github.com/foo/bar
COPY . /go/src/github.com/foo/bar
# ONBUILD RUN go-wrapper download
RUN go install
ENTRYPOINT /go/bin/bar
EXPOSE 51672
my command to build the image:
docker build -t bar .
my command to launch the docker container:
docker run -p 51672:51672 --name bar-container bar
Other info:
-
client program runs fine from within the docker container
-
connecting to a regular rest endpoint works fine (http2, grpc related?)
-
running the
lsof
command in OS X yields these results$lsof -i | grep 51672 com.docke 984 oldDave 21u IPv4 0x72779547e3a32c89 0t0 TCP *:51672 (LISTEN) com.docke 984 oldDave 22u IPv6 0x72779547cc0fd161 0t0 TCP localhost:51672 (LISTEN)
-
here's a snippet of my server code:
server := &Server{} endpoint := "localhost:51672" lis, err := net.Listen("tcp", endpoint) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer(grpc.Creds(creds)) pb.RegisterExpServiceServer(s, server) // Register reflection service on gRPC server. reflection.Register(s) log.Info("Starting Exp server: ", endpoint) if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) }
答案1
得分: 52
当你指定一个主机名或IP地址来监听时(在这种情况下是localhost,解析为127.0.0.1),那么你的服务器只会监听该IP地址。
当你在Docker容器外部时,监听localhost并不是一个问题。如果你的服务器只监听127.0.0.1:51672,那么你的客户端可以轻松连接到它,因为连接也是从127.0.0.1发起的。
当你在Docker容器内运行服务器时,它仍然只会监听127.0.0.1:51672。127.0.0.1是一个本地回环地址,无法从容器外部访问。
当你使用"-p 51672:51672"启动Docker容器时,它会将流量转发到127.0.0.1:51672,转发到容器的IP地址,对我来说是172.17.0.2。
容器在docker0网络接口中获得一个IP地址(可以使用"ip addr ls"命令查看)。
因此,当流量转发到172.17.0.2:51672的容器时,那里没有正在监听的内容,连接尝试失败。
解决方法:
问题出在监听端点上:
endpoint := "localhost:51672"
要解决问题,将其更改为
endpoint := ":51672"
这将使你的服务器监听所有容器的IP地址。
附加信息:
当你在Docker容器中暴露端口时,Docker会创建iptables规则来进行实际的转发。参见这里。你可以使用以下命令查看这些规则:
iptables -n -L
iptables -t nat -n -L
英文:
When you specify a hostname or IP address to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.
Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:51672, then your client can easily connect to it since the connection is also made from 127.0.0.1.
When you run your server inside a Docker container, it'll only listen on 127.0.0.1:51672 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.
When you fire up the docker container with "-p 51672:51672", it'll forward traffic heading to 127.0.0.1:51672 to the container's IP address, which in my case is 172.17.0.2.
The container gets an IP addresses within the docker0 network interface (which you can see with the "ip addr ls" command)
So, when your traffic gets forwarded to the container on 172.17.0.2:51672, there's nothing listening there and the connection attempt fails.
The fix:
The problem is with the listen endpoint:
endpoint := "localhost:51672"
To fix your problem, change it to
endpoint := ":51672"
That'll make your server listen on all it container's IP addresses.
Additional info:
When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules
with:
iptables -n -L
iptables -t nat -n -L
答案2
得分: 0
如果您使用Docker容器来运行gRPC服务,您需要确保gRPC服务
和gRPC客户端
在同一个桥接网络上。
英文:
If you use docker container to run grpc service,you should make sure grpc service
and grpc client
on ths same bridge
答案3
得分: 0
如果您正在使用Docker容器,您可以通过IP定义网络,并将此IP分配给您的IP地址(例如:178.20.0.5)。
英文:
if you are using docker container, u can define network by IP and give this IP to your IP address(like: 178.20.0.5).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论