Olá Habr! Apresento a você a tradução do artigo 
“Go, gRPC and Docker” de Mat Evans.
Existem muitos artigos sobre o compartilhamento do Go e do Docker. Criar contêineres que possam interagir com os clientes e entre eles é muito fácil. A seguir, é apresentado um pequeno exemplo de como isso é feito em um nível básico.
O que criamos?
Criaremos cliente e servidor muito simples, interagindo entre si usando o 
gRPC . O servidor estará localizado dentro do contêiner do 
Docker para que possa ser facilmente implantado.
Suponha que precisamos de um serviço que receba uma string de um cliente e retorne uma string com uma ordem inversa de caracteres. Por exemplo, envie um "gato" e obtenha uma "corrente" em resposta.
arquivo .proto
O arquivo 
.protocolo descreve quais operações nosso serviço executará e quais dados serão trocados. Crie a pasta 
proto no projeto e o arquivo 
reverse.proto nele
syntax = "proto3"; package reverse; service Reverse { rpc Do(Request) returns (Response) {} } message Request { string message = 1; } message Response { string message = 1; } 
Uma função chamada remotamente no servidor e retorna dados ao cliente é marcada como 
rpc . As estruturas de dados usadas para trocar informações entre os nós em interação são marcadas como 
mensagem . Cada campo de mensagem deve receber um número de sequência. Nesse caso, nossa função recebe mensagens do tipo 
Request do cliente e retorna mensagens do tipo 
Response .
Depois de 
criarmos um arquivo 
.proto , é necessário obter o arquivo 
.go do nosso serviço. Para fazer isso, execute o seguinte comando do console na pasta 
proto :
 $ protoc -I . reverse.proto --go_out=plugins=grpc:. 
Obviamente, primeiro você precisa 
criar o gRPC .
A execução do comando acima criará um novo arquivo 
.go que contém métodos para criar o cliente, o servidor e as mensagens que eles trocam. Se chamarmos 
godoc , veremos o seguinte:
 $ 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 .... 
Cliente
Seria bom se nosso cliente trabalhasse assim:
 reverse "this is a test" tset a si siht 
Aqui está o código que cria o cliente 
gRPC usando estruturas de dados geradas a partir do arquivo 
.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) } 
Servidor
O servidor usará o mesmo arquivo 
.go gerado. No entanto, apenas define a interface do servidor, mas precisamos implementar a lógica por conta própria:
 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
Suponho que você saiba o que 
é o 
Docker e para que serve. Aqui está o nosso 
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 
O código de montagem da imagem do 
Docker está escrito aqui. Vamos analisá-lo linha por linha.
 FROM golang:1.12 
Este comando significa que queremos criar uma imagem do nosso aplicativo com base em uma imagem criada anteriormente, ou seja, 
golang . Esta é uma imagem do 
Docker com um ambiente já configurado para criar e executar programas escritos no 
Go .
 ADD . /go/src/github.com/matzhouse/go-grpc/server 
Este comando copia o código fonte do nosso aplicativo no 
contêiner GOPATH / src .
 RUN go install github.com/matzhouse/go-grpc/server 
Este comando coleta nosso aplicativo das fontes copiadas para o contêiner e o instala na 
pasta GOPATH / bin container.
 ENTRYPOINT ["/go/bin/server"] 
Este comando configura o contêiner para funcionar como um programa executável. Nele, indicamos o caminho para o aplicativo executável e, se necessário, os argumentos da linha de comando.
 EXPOSE 5300 
Com este comando, dizemos ao contêiner quais portas devem ser acessíveis externamente.
Início do servidor
Precisamos executar o contêiner com nosso aplicativo de servidor.
Primeiro, você precisa criar a imagem com base nas instruções do 
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 
Agora podemos ver esta imagem na lista:
 $ docker images REPOSITORY TAG IMAGE ID ... matzhouse/grpc-server latest 008e09b9aebd ... 
Ótimo! Temos uma imagem do nosso aplicativo de servidor, com a qual você pode iniciar seu contêiner usando o seguinte comando:
 $ docker run -it -p 5300:5300 matzhouse/grpc-server 
Nesse caso, o chamado 
encaminhamento de porta . Observe que para isso precisamos da instrução 
EXPOSE e do argumento 
-p .
Lançamento do cliente
A conteinerização do cliente não dará grandes vantagens, então vamos começar da maneira usual:
 $ go build -o reverse $ ./reverse "this is a test" tset a si siht 
Obrigado pela leitura!