はじめに
dockerを使ったgrpcをまとめたいと思います。
内容は、クイックスタートに準拠しています。
レポジトリーを作りました。
gRPCとは
gRPCとは、http2とバイナリを使用した高速通信可能なgoogleが開発したPRCフレームワークです。
プロトコルバッファとは
構造化データ定義し、シリアライズするためのオープンソースメカニズムです。
protocコマンドを打つことで、goファイルを自動生成します。
コーディング
Dockerをbuild
ファイル構成
.
├── client
│ ├── Dockerfile
│ └── go_grpc
│ └── bin
│ └── go_starter
├── docker-compose.yml
└── server
├── Dockerfile
└── go_grpc
└── bin
└── go_starter
Dockerfile
FROM golang:1.19-buster
ENV PROTOBUF_VERSION 3.17.3
RUN apt-get update \
&& apt-get install -y protobuf-compiler unzip --no-install-recommends \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /practice-grpc
COPY . /practice-grpc
## build時のみ使いたいので、runで実行。
RUN chmod +x go_grpc/bin/go_starter && go_grpc/bin/go_starter
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
docker-compose.yml
version: '3.7'
services:
server:
build: ./server
container_name: "server-grpc"
volumes:
- ./server:/practice-grpc
ports:
- "8080:8080"
tty: true
client:
build: ./client
container_name: "client-grpc"
volumes:
- ./client:/practice-grpc
tty: true
go mod initコマンドも合わせて行っています。
go_grpc/bin/go_starter
#!/usr/bin/env bash
set -euo pipefail
function exits() {
local cwd="$1"
local File="${cwd}/go.mod"
local c_dir=${cwd##*/}
if [ -f "${File}" ]; then
echo "${File} exist"
else
cd "${c_dir}"
go mod init "${c_dir}"
fi
}
function main() {
local cwd
cwd="$(cd "$(dirname "$0")/.." && pwd)"
exits "${cwd}"
}
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
main "$@"
fi
buildします。
docker compose up
ここまでで、初期設定は終わりです。
protoコマンドを実行
ディレクトリーとファイルを作ります。
mkdir server/go_grpc/pb server/go_grpc/proto
touch server/go_grpc/proto/route_guide.proto
server/go_grpc/proto/Helloworld.proto
syntax = "proto3";
package helloworld;
option go_package = "./pb"; // 自動生成されるgoファイルの出力先を指定します。
// サービスメソッドで使用されるすべてのリクエスト
// およびレスポンスタイプのプロトコルバッファメッセージタイプ定義
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
protoc -I. --go_out=. --go-grpc_out=. proto/*.proto
-Iは起点になっているディレクトリを表しています。.はカレントディレクトリ。
--go_outはgoファイルに変換することを意味しています。
pb/helloworld.pb.go
pb/helloworld_grpc.pb.go
の二つができました。
同じことをclient側でもします。
server側
server側もclient側も見やすくするために書き直しました。
server/main.go
package main
import (
"context"
"log"
"net"
pb "go_grpc/pb"
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", "server:8080")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
client側
client/main.go
package main
import (
"context"
"log"
"time"
pb "go_grpc/pb"
grpc "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func main() {
conn, err := grpc.Dial("server:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "yuki"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
通信
準備が整ったので、実際に通信をしてみます。
最終的なファイル構成
.
├── client
│ ├── Dockerfile
│ └── go_grpc
│ ├── bin
│ │ └── go_starter
│ ├── client
│ │ └── main.go
│ ├── go.mod
│ ├── go.sum
│ ├── pb
│ │ ├── Helloworld.pb.go
│ │ └── Helloworld_grpc.pb.go
│ └── proto
│ └── Helloworld.proto
├── docker-compose.yml
└── server
├── Dockerfile
└── go_grpc
├── bin
│ └── go_starter
├── go.mod
├── go.sum
├── pb
│ ├── Helloworld.pb.go
│ └── Helloworld_grpc.pb.go
├── proto
│ └── Helloworld.proto
└── server
└── main.go
server-grpcコンテナ内に入り以下のコマンドを実行します。
cd go_grpc
go run server/main.go
server
2022/12/31 05:25:49 server listening at 172.18.0.3:8080
2022/12/31 05:25:55 Received: yuki
client-grpcコンテナ内に入り以下のコマンドを実行します。
cd go_grpc
go run client/main.go
client
2022/12/31 05:25:58 Greeting: Hello yuki
期待通りの動きをしています。