minikube上のPod間でgRPCを使ってHello world

https://github.com/shmn7iii/grpc_tutorial_hello_k8s

ながい。

概要

とりあえず、HelloしてくれるgRPCのコードはQuickStartで使ったコードを流用する。Pod達はローカルのminikube上で動かす。

構成

grpc_tutorial_hello_k8s/ ├ client/ # クライアント用 │ ├ Dockerfile │ └ main.go ├ server/ # サーバー用 │ ├ Dockerfile │ └ main.go ├ k8s/ # K8s設定用 │ └ manifest.yaml ├ pb/ # 自動生成 │ ├ hello_k8s.pb.go │ └ hello_k8s_grpc.pb.go ├ go.mod ├ go.sum └ hello_k8s.proto # protocol buffer用

実行ファイルを用意

hello_k8s.proto

syntax = "proto3"; package hello_k8s; option go_package = "pb/"; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }

server/main.go

package main import ( "context" "log" "net" pb "github.com/shmn7iii/grpc_tutorial_hello_k8s/pb" "google.golang.org/grpc" ) const ( port = ":50051" ) 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", port) 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/main.go

package main import ( "context" "log" "os" "time" pb "github.com/shmn7iii/grpc_tutorial_hello_k8s/pb" "google.golang.org/grpc" ) const ( defaultAddress = "localhost:50051" ) func main() { address := defaultAddress // 引数からアドレスを指定 if len(os.Args) > 1 { address = os.Args[1] } //gRPC接続を開く conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) if err != nil { log.Fatalf("did not connect: %v", err) log.Printf("did not connect: %v", err) } defer conn.Close() c := pb.NewGreeterClient(conn) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() // Say Hello! r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "world"}) if err != nil { log.Fatalf("could not greet: %v", err) } log.Printf("Greeting: %s", r.GetMessage()) }

Dockerイメージ用意

Docker Compose的にローカルのDockerfile読んでくれるのかなって思ってたらそうでもないらしい。どうやらビルドしたイメージを指定する必要がある。

用意したDockerfileは以下。

Server/Dockerfile

FROM golang:1.17.4-alpine RUN apk update \ && apk add git \ && git clone https://github.com/shmn7iii/grpc_tutorial_hello_k8s.git \ && go install google.golang.org/protobuf/cmd/[email protected] \ && go install google.golang.org/grpc/cmd/[email protected] WORKDIR /go/grpc_tutorial_hello_k8s CMD ["go", "run", "server/main.go"]

Client/Dockerfile

FROM golang:1.17.4-alpine RUN apk update \ && apk add git \ && git clone https://github.com/shmn7iii/grpc_tutorial_hello_k8s.git \ && go install google.golang.org/protobuf/cmd/[email protected] \ && go install google.golang.org/grpc/cmd/[email protected] WORKDIR /go/grpc_tutorial_hello_k8s CMD ["go", "run", "client/main.go"]
(内容ほぼ一緒だから環境変数とかで条件分岐させた方がよさそう)
(てかクライアント側のCMD意味ない。アドレスしていないからローカルに繋ぎ始めるけどそのまま応答待ち続けてる。都合いいから放置してるけどほんとはなんとかしたい)

K8sマニフェストを用意

用意したマニフェストは以下。

k8s/manifest.yaml

apiVersion: v1 kind: Pod metadata: name: server1 spec: containers: - name: server1 image: grpc_tutorial_hello_k8s_server imagePullPolicy: Never ports: - containerPort: 50051 --- apiVersion: v1 kind: Pod metadata: name: client1 spec: containers: - name: client1 image: grpc_tutorial_hello_k8s_client imagePullPolicy: Never --- apiVersion: v1 kind: Pod metadata: name: client2 spec: containers: - name: client2 image: grpc_tutorial_hello_k8s_client imagePullPolicy: Never

実行

手順を追う。

作業ディレクトリはGitHubのレポ

# minikubeをスタート $ minikube start # minikubeのDockerクライアントへ変更 $ eval $(minikube docker-env) # imageをbuild $ docker image build -t grpc_tutorial_hello_k8s_server ./server $ docker image build -t grpc_tutorial_hello_k8s_client ./client # k8sで起動 $ kubectl apply -f k8s/manifest.yaml pod/server1 created pod/client1 created pod/client2 created # Podの詳細を確認 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES client1 1/1 Running 0 66s 172.17.0.5 minikube <none> <none> client2 1/1 Running 0 66s 172.17.0.3 minikube <none> <none> server1 1/1 Running 0 66s 172.17.0.4 minikube <none> <none>

これで構築完了。

次に動作確認。別ターミナルで

# サーバー側のログを追う $ kubectl logs -f server1 go: downloading google.golang.org/grpc v1.42.0 go: downloading google.golang.org/protobuf v1.27.1 go: downloading google.golang.org/genproto v0.0.0-20211207154714-918901c715cf go: downloading golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b go: downloading github.com/golang/protobuf v1.5.2 go: downloading golang.org/x/sys v0.0.0-20211205182925-97ca703d548d go: downloading golang.org/x/text v0.3.7 2021/12/13 10:39:08 server listening at [::]:50051

もう一個別ターミナルで

# クライアントPodに入る $ kubectl exec -it client1 -- /bin/sh # IPget podsで確認済み、挨拶してみる /go/grpc_tutorial_hello_k8s # go run client/main.go 172.17.0.4:50051 2021/12/13 10:39:37 Greeting: Hello world

クライアント側からHello worldすることができた。