gRPCをdockerで動かしたぜんぜんわからんからメモ
gRPCを学ぼうとしているけどぜんぜんわからん
まずGo言語もわからん
プロトコルバッファーもわからん
まともに動かすのも難儀する
下記URLを参考にひとまず動くものを手にしようと思ってもうまくいかなかったり四苦八苦したので、Bidirectional streaming RPC を動かしたメモを残す
goでgRPCの4つの通信方式やってみた(Dockerのサンプルあり) - Qiita
詰まったポイントとしては、protoファイルに option go_package の記述がないことでエラーになったことの対処だったり、
Dockerにてホスト側の作業ディレクトリの親の親ディレクトリをボリュームマウントすることで不要なファイルまでマウントしてので、作業ディレクトリ配下で完結するようにしたり、
あとコンテナに入らないでコマンド実行する方法をまとめた。
環境
・win10 vbox Ubuntu
・docker、docker-compose インストール済
準備
ホスト側作業ディレクトリ
/var/docker/grpc-docker
ファイル・フォルダ構成
./docker-compose.yml
./grpc/Dockerfile
./grpc/src/proto/chat.proto
./grpc/src/server/main.go
./grpc/src/client/main.go
./grpc/src/pb/chat ※空フォルダ
./docker-compose.yml
version: "3.7"
services:
go-grpc:
build:
context: ./grpc/
dockerfile: Dockerfile
container_name: "grpc"
volumes:
- ./grpc/src/:/go-grpc
tty: true
privileged: true
./grpc/Dockerfile
FROM golang:1.13-stretch
SHELL ["/bin/bash", "-c"]
RUN apt update && apt-get install -y vim unzip# install protc
WORKDIR /protoc
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.2/protoc-3.11.2-linux-x86_64.zip
RUN unzip protoc-3.11.2-linux-x86_64.zip
RUN ln -s /protoc/bin/protoc /bin/protoc# golang
WORKDIR /go-grpc
ENV GO111MODULE on
RUN go get -u github.com/golang/protobuf/protoc-gen-go
./grpc/src/proto/chat.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.chat";
option java_outer_classname = "ChatProto";package chat;
option go_package = "./"; //上記参考サイトのものに追記
service Chat {
rpc Chat (stream ChatRequest) returns (stream ChatReply) {}
}message ChatRequest {
string message = 1;
}message ChatReply {
string message = 1;
}
./grpc/src/server/main.go
package main
import (
"fmt"
"io"
"log"
"net"
"time"pb "grpc-docker/pb/chat"
"github.com/pkg/errors"
"google.golang.org/grpc"
)const port = ":50051"
// ServerBidirectional is server
type ServerBidirectional struct {
pb.UnimplementedChatServer
}func request(stream pb.Chat_ChatServer, message string) error {
reply := fmt.Sprintf("%sを受け取ったよ!ありがとう^^", message)
return stream.Send(&pb.ChatReply{
Message: reply,
})
}// Chat クライアントから受け取った言葉に、言葉を返す
func (s *ServerBidirectional) Chat(stream pb.Chat_ChatServer) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
message := in.GetMessage()
fmt.Println("受取:", message)if err := request(stream, message); err != nil {
return err
}
time.Sleep(time.Second * 1)
}
}func set() error {
lis, err := net.Listen("tcp", port)
if err != nil {
return errors.Wrap(err, "ポート失敗")
}
s := grpc.NewServer()
var server ServerBidirectional
pb.RegisterChatServer(s, &server)
if err := s.Serve(lis); err != nil {
return errors.Wrap(err, "サーバ起動失敗")
}
return nil
}func main() {
fmt.Println("起動")
if err := set(); err != nil {
log.Fatalf("%v", err)
}
}
./grpc/src/client/main.go
package main
import (
"context"
"io"
"log"
"time""github.com/pkg/errors"
pb "grpc-docker/pb/chat"
func receive(stream pb.Chat_ChatClient) error {
waitc := make(chan struct{})
go func() {
for {
in, err := stream.Recv()
if err == io.EOF {
close(waitc)
return
}
if err != nil {
log.Fatalf("エラー: %v", err)
}
log.Printf("サーバから:%s", in.Message)// お返し
stream.Send(&pb.ChatRequest{
Message: time.Now().Format("2006-01-02 15:04:05"),
})
}
}()
<-waitc
return nil
}func request(stream pb.Chat_ChatClient) error {
return stream.Send(&pb.ChatRequest{
Message: "こんにちは",
})
}func chat(client pb.ChatClient) error {
stream, err := client.Chat(context.Background())
if err != nil {
return err
}
if err := request(stream); err != nil {
return err
}
if err := receive(stream); err != nil {
return err
}
stream.CloseSend()
return nil
}func exec() error {
address := "localhost:50051"
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
return errors.Wrap(err, "コネクションエラー")
}
defer conn.Close()
client := pb.NewChatClient(conn)
return chat(client)
}func main() {
if err := exec(); err != nil {
log.Println(err)
}
}
ファイル生成
Dockerコンテナを立ち上げる
docker-compose up -d
下記コマンドを実行し、go moduleの初期化を行う
docker-compose exec go-grpc go mod init grpc-docker
すると ./grpc/src/go.mod が生成される
下記コマンドを実行し、gRPCファイルの生成
docker-compose exec go-grpc protoc --proto_path ./proto --go_out=plugins=grpc:./pb/chat chat.proto
すると ./grpc/src/pb/chat/chat.pb.go が生成される
サーバとクライアントの実行
下記コマンドを実行し、gRPCサーバを起動する
docker-compose exec go-grpc go run server/main.go
すると ./grpc/src/go.sum が生成される
下記コマンドを実行し、gRPCクライアントを起動する
docker-compose exec go-grpc go run client/main.go
すると下記スクショのようにサーバ側とクライアント側で出力が表示される。
ようやくgRPC学習のスタートラインに立てた感
次はgRPC-webを動かす方法を調べる
暗中模索
PS
A Tour of Go だけじゃ全然わからんけど、
とほほのGo言語入門 - とほほのWWW入門 を併せて参考にすると理解が捗った。