web-dev-qa-db-ja.com

ローカルDockerコンテナーで実行されているGo GRPCサーバーに接続できません

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

他の情報:

  • クライアントプログラムは、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)
    }
    
14
david webber

待機するホスト名または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
24
olafure