Go grpcサービスを利用しています。 Mac、シエラで開発しています。ローカルでサービスに対してgrpcクライアントを実行する場合、問題はありませんが、Dockerコンテナー内の同じサービスに対して同じクライアントを実行する場合、次のエラーが発生します。
transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing
これは私のドッカーファイルです:
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
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に解決されるlocalhost)、サーバーはその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ルールを作成します。 this を参照してください。これらのルールは次の方法で表示できます。
iptables -n -L
iptables -t nat -n -L