Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels
„Go, gRPC and Docker“ von Mat Evans.
Es gibt viele Artikel über das Teilen von Go und Docker. Das Erstellen von Containern, die mit Kunden und untereinander interagieren können, ist sehr einfach. Das Folgende ist ein kleines Beispiel dafür, wie dies auf einer grundlegenden Ebene durchgeführt wird.
Was schaffen wir?
Wir werden sehr einfache Clients und Server erstellen, die mithilfe von
gRPC miteinander interagieren. Der Server befindet sich im
Docker- Container, sodass er problemlos bereitgestellt werden kann.
Angenommen, wir benötigen einen Dienst, der eine Zeichenfolge von einem Client empfängt und eine Zeichenfolge mit umgekehrter Zeichenreihenfolge zurückgibt. Senden Sie beispielsweise eine "Katze" und erhalten Sie eine "aktuelle" Antwort.
.proto-Datei
.proto- file beschreibt, welche Vorgänge unser Service ausführen und welche Daten er austauschen wird. Erstellen Sie den
Proto- Ordner im Projekt und die Datei
reverse.proto darin
syntax = "proto3"; package reverse; service Reverse { rpc Do(Request) returns (Response) {} } message Request { string message = 1; } message Response { string message = 1; }
Eine Funktion, die remote auf dem Server aufgerufen wird und Daten an den Client zurückgibt, wird als
rpc markiert. Datenstrukturen, die zum Informationsaustausch zwischen interagierenden Knoten verwendet werden, werden als
Nachricht markiert. Jedem Nachrichtenfeld muss eine Sequenznummer zugewiesen werden. In diesem Fall empfängt unsere Funktion Nachrichten vom
Anforderungstyp vom Client und gibt Nachrichten vom
Antworttyp zurück .
Sobald wir eine
.proto- Datei erstellt haben, ist es notwendig, die
.go- Datei unseres Dienstes
abzurufen . Führen Sie dazu den folgenden Konsolenbefehl im
Proto- Ordner aus:
$ protoc -I . reverse.proto --go_out=plugins=grpc:.
Natürlich müssen Sie zuerst
gRPC erstellen .
Durch Ausführen des obigen Befehls wird eine neue
GO- Datei erstellt, die Methoden zum Erstellen des Clients, des Servers und der Nachrichten enthält, die sie austauschen. Wenn wir
Godoc nennen, werden wir Folgendes sehen:
$ 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 ....
Kunde
Es wäre schön, wenn unser Kunde so arbeiten würde:
reverse "this is a test" tset a si siht
Hier ist der Code, der den
gRPC- Client mithilfe von Datenstrukturen erstellt, die aus der
.proto- Datei generiert wurden:
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) }
Server
Der Server verwendet dieselbe generierte
GO- Datei. Es definiert jedoch nur die Serverschnittstelle, aber wir müssen die Logik selbst implementieren:
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
Ich gehe davon aus, dass Sie wissen, was
Docker ist und wofür es ist. Hier ist unser
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
Der Assembler-Code für das
Docker- Image wird hier geschrieben. Wir werden es Zeile für Zeile analysieren.
FROM golang:1.12
Dieser Befehl bedeutet, dass wir ein Image unserer Anwendung auf der Grundlage eines zuvor erstellten Images erstellen möchten, nämlich
Golang . Dies ist ein
Docker- Image mit einer bereits konfigurierten Umgebung zum Erstellen und Ausführen von in
Go geschriebenen Programmen.
ADD . /go/src/github.com/matzhouse/go-grpc/server
Dieser Befehl kopiert den Quellcode unserer Anwendung in den
GOPATH / src- Container.
RUN go install github.com/matzhouse/go-grpc/server
Dieser Befehl sammelt unsere Anwendung aus den in den Container kopierten Quellen und installiert sie im Containerordner
GOPATH / bin .
ENTRYPOINT ["/go/bin/server"]
Dieser Befehl konfiguriert den Container so, dass er als ausführbares Programm arbeitet. Darin geben wir den Pfad zur ausführbaren Datei der Anwendung und gegebenenfalls Befehlszeilenargumente an.
EXPOSE 5300
Mit diesem Befehl teilen wir dem Container mit, auf welche Ports von außen zugegriffen werden soll.
Serverstart
Wir müssen den Container mit unserer Serveranwendung ausführen.
Zuerst müssen Sie das Image basierend auf den Anweisungen aus der
Docker-Datei erstellen :
$ 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
Jetzt können wir dieses Bild in der Liste sehen:
$ docker images REPOSITORY TAG IMAGE ID ... matzhouse/grpc-server latest 008e09b9aebd ...
Großartig! Wir haben ein Image unserer Serveranwendung, mit der Sie den Container mit dem folgenden Befehl starten können:
$ docker run -it -p 5300:5300 matzhouse/grpc-server
In diesem Fall ist das sogenannte
Portweiterleitung . Beachten Sie, dass wir dafür sowohl die
EXPOSE- Anweisung als auch das
-p- Argument benötigen.
Client-Start
Die Containerisierung des Clients bringt keine großen Vorteile. Beginnen wir also auf die übliche Weise:
$ go build -o reverse $ ./reverse "this is a test" tset a si siht
Danke fürs Lesen!