Bonjour, Habr! Je vous présente la traduction de l'article
«Go, gRPC et Docker» de Mat Evans.
Il existe de nombreux articles sur le partage de Go et Docker. La création de conteneurs pouvant interagir avec les clients et entre eux est très simple. Ce qui suit est un petit exemple de la façon dont cela est fait au niveau de base.
Que créons-nous?
Nous allons créer un client et un serveur très simples, interagissant les uns avec les autres à l'aide de
gRPC . Le serveur sera situé à l'intérieur du conteneur
Docker afin de pouvoir être facilement déployé.
Supposons que nous ayons besoin d'un service qui reçoit une chaîne d'un client et renvoie une chaîne avec un ordre de caractères inversé. Par exemple, envoyez un «chat» et obtenez un «courant» en réponse.
fichier .proto
Le fichier
.proto décrit les opérations que notre service effectuera et les données qu'il échangera. Créez le dossier
proto dans le projet et le fichier
reverse.proto dedans
syntax = "proto3"; package reverse; service Reverse { rpc Do(Request) returns (Response) {} } message Request { string message = 1; } message Response { string message = 1; }
Une fonction qui est appelée à distance sur le serveur et renvoie des données au client est marquée comme
rpc . Les structures de données utilisées pour échanger des informations entre des nœuds en interaction sont marquées comme
message . Chaque champ de message doit recevoir un numéro de séquence. Dans ce cas, notre fonction reçoit des messages de type
Request du client et retourne des messages de type
Response .
Une fois que nous avons créé un fichier
.proto , il est nécessaire d'obtenir le fichier
.go de notre service. Pour ce faire, exécutez la commande de console suivante dans le dossier
proto :
$ protoc -I . reverse.proto --go_out=plugins=grpc:.
Bien sûr, vous devez d'abord
construire gRPC .
L'exécution de la commande ci-dessus créera un nouveau fichier
.go contenant les méthodes de création du client, du serveur et des messages qu'ils échangent. Si nous appelons
godoc , nous verrons ce qui suit:
$ godoc . PACKAGE DOCUMENTATION package reverse import "." Package reverse is a generated protocol buffer package. It is generated from these files: reverse.proto It has these top-level messages: Request Response ....
Client
Ce serait bien si notre client travaillait comme ceci:
reverse "this is a test" tset a si siht
Voici le code qui crée le client
gRPC à l'aide de structures de données générées à partir du fichier
.proto :
package main import ( "context" "fmt" "os" pb "github.com/matzhouse/go-grpc/proto" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func main() { opts := []grpc.DialOption{ grpc.WithInsecure(), } args := os.Args conn, err := grpc.Dial("127.0.0.1:5300", opts...) if err != nil { grpclog.Fatalf("fail to dial: %v", err) } defer conn.Close() client := pb.NewReverseClient(conn) request := &pb.Request{ Message: args[1], } response, err := client.Do(context.Background(), request) if err != nil { grpclog.Fatalf("fail to dial: %v", err) } fmt.Println(response.Message) }
Serveur
Le serveur utilisera le même fichier
.go généré. Cependant, il ne définit que l'interface du serveur, mais nous devons implémenter la logique par nous-mêmes:
package main import ( "net" pb "github.com/matzhouse/go-grpc/proto" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func main() { listener, err := net.Listen("tcp", ":5300") if err != nil { grpclog.Fatalf("failed to listen: %v", err) } opts := []grpc.ServerOption{} grpcServer := grpc.NewServer(opts...) pb.RegisterReverseServer(grpcServer, &server{}) grpcServer.Serve(listener) } type server struct{} func (s *server) Do(c context.Context, request *pb.Request) (response *pb.Response, err error) { n := 0
Docker
Je suppose que vous savez ce qu'est
Docker et à quoi il sert. Voici notre
Dockerfile :
FROM golang:1.12 ADD . /go/src/github.com/matzhouse/go-grpc/server RUN go install github.com/matzhouse/go-grpc/server ENTRYPOINT ["/go/bin/server"] EXPOSE 5300
Le code d'assemblage de l'image
Docker est écrit ici. Nous allons l'analyser ligne par ligne.
FROM golang:1.12
Cette commande signifie que nous voulons créer une image de notre application sur la base d'une image précédemment créée, à savoir
golang . Il s'agit d'une image
Docker avec un environnement déjà configuré pour créer et exécuter des programmes écrits en
Go .
ADD . /go/src/github.com/matzhouse/go-grpc/server
Cette commande copie le code source de notre application dans le
conteneur GOPATH / src .
RUN go install github.com/matzhouse/go-grpc/server
Cette commande collecte notre application à partir des sources copiées dans le conteneur et l'installe dans le
dossier du conteneur
GOPATH / bin .
ENTRYPOINT ["/go/bin/server"]
Cette commande configure le conteneur pour fonctionner comme un programme exécutable. Nous y indiquons le chemin vers l'exécutable de l'application et, si nécessaire, les arguments de la ligne de commande.
EXPOSE 5300
Avec cette commande, nous indiquons au conteneur quels ports doivent être accessibles de l'extérieur.
Démarrage du serveur
Nous devons exécuter le conteneur avec notre application serveur.
Vous devez d'abord créer l'image en fonction des instructions du
Dockerfile :
$ sudo docker build -t matzhouse/grpc-server . Sending build context to Docker daemon 31.76 MB Step 1/5 : FROM golang ---> a0c61f0b0796 Step 2/5 : ADD . /go/src/github.com/matzhouse/go-grpc ---> 9508be6501c1 Removing intermediate container 94dc6e3a9a20 Step 3/5 : RUN go install github.com/matzhouse/go-grpc/server ---> Running in f3e0b993a420 ---> f7a0370b7f7d Removing intermediate container f3e0b993a420 Step 4/5 : ENTRYPOINT /go/bin/server ---> Running in 9c9619e45df4 ---> fb34dfe1c0ea Removing intermediate container 9c9619e45df4 Step 5/5 : EXPOSE 5300 ---> Running in 0403390af135 ---> 008e09b9aebd Removing intermediate container 0403390af135 Successfully built 008e09b9aebd
Maintenant, nous pouvons voir cette image dans la liste:
$ docker images REPOSITORY TAG IMAGE ID ... matzhouse/grpc-server latest 008e09b9aebd ...
Super! Nous avons une image de notre application serveur, avec laquelle vous pouvez lancer son conteneur en utilisant la commande suivante:
$ docker run -it -p 5300:5300 matzhouse/grpc-server
Dans ce cas, le soi-disant
redirection de port . Notez que pour cela, nous avons besoin à la fois de l'instruction
EXPOSE et de l'argument
-p .
Lancement client
La conteneurisation du client ne donnera pas de gros avantages, alors commençons comme d'habitude:
$ go build -o reverse $ ./reverse "this is a test" tset a si siht
Merci d'avoir lu!