web-dev-qa-db-fra.com

Impossible de se connecter au serveur Go GRPC s'exécutant dans un conteneur Docker local

J'ai un service go grpc. Je développe sur un mac, sierra. Lorsque vous exécutez un client grpc contre le service localement, tout va bien, mais lorsque vous exécutez le même client contre le même service dans le conteneur Docker, j'obtiens cette erreur:

transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing

voici mon fichier 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

ma commande pour construire l'image:

docker build -t bar .

ma commande pour lancer le conteneur docker:

docker run -p 51672:51672 --name bar-container bar

Autre info:

  • le programme client fonctionne correctement à partir du conteneur Docker
  • la connexion à un point de terminaison de repos normal fonctionne correctement (http2, lié à grpc?)
  • l'exécution de la commande lsof dans OS X donne ces résultats

    $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)
    
  • voici un extrait de mon code serveur:

    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

Lorsque vous spécifiez un nom d'hôte ou une adresse IP pour écouter (dans ce cas localhost qui se résout en 127.0.0.1), votre serveur n'écoutera que sur cette adresse IP.

L'écoute sur localhost n'est pas un problème lorsque vous êtes en dehors d'un conteneur Docker. Si votre serveur n'écoute que sur 127.0.0.1:51672, votre client peut facilement s'y connecter car la connexion est également établie à partir de 127.0.0.1.

Lorsque vous exécutez votre serveur à l'intérieur d'un conteneur Docker, il n'écoutera que le 127.0.0.1:51672 comme auparavant. Le 127.0.0.1 est une adresse de bouclage locale et n'est pas accessible en dehors du conteneur.

Lorsque vous lancez le conteneur Docker avec "-p 51672: 51672", il transfère le titre du trafic vers 127.0.0.1:51672 vers l'adresse IP du conteneur, qui dans mon cas est 172.17.0.2.

Le conteneur obtient une adresse IP dans l'interface réseau docker0 (que vous pouvez voir avec la commande "ip addr ls")

Ainsi, lorsque votre trafic est transféré vers le conteneur le 172.17.0.2:51672, il n'y a rien à écouter et la tentative de connexion échoue.

Le correctif:

Le problème est avec le point de terminaison d'écoute:

endpoint := "localhost:51672"

Pour résoudre votre problème, changez-le en

endpoint := ":51672"

Cela fera que votre serveur écoutera toutes les adresses IP de son conteneur.

Informations supplémentaires:

Lorsque vous exposez des ports dans un conteneur Docker, Docker crée des règles iptables pour effectuer le transfert réel. Voir ceci . Vous pouvez afficher ces règles avec:

iptables -n -L 
iptables -t nat -n -L
24
olafure