无法连接到本地 Docker 容器中的 Go GRPC 服务器 运行
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 容器中运行良好
- 连接到常规休息端点工作正常(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)
}
当您指定要侦听的主机名或 IP 地址(在本例中为解析为 127.0.0.1 的本地主机)时,您的服务器将仅侦听该 IP 地址。
当您在 Docker 容器之外时,在本地主机上监听不是问题。如果您的服务器仅侦听 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 规则来进行实际转发。参见 this。你可以查看这些规则
与:
iptables -n -L
iptables -t nat -n -L
如果你使用 docker 容器到 运行 grpc 服务,你应该确保 grpc service
和 grpc client
在同一个桥上
我有一个 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 容器中运行良好
- 连接到常规休息端点工作正常(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) }
当您指定要侦听的主机名或 IP 地址(在本例中为解析为 127.0.0.1 的本地主机)时,您的服务器将仅侦听该 IP 地址。
当您在 Docker 容器之外时,在本地主机上监听不是问题。如果您的服务器仅侦听 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 规则来进行实际转发。参见 this。你可以查看这些规则 与:
iptables -n -L
iptables -t nat -n -L
如果你使用 docker 容器到 运行 grpc 服务,你应该确保 grpc service
和 grpc client
在同一个桥上