Go言語でgRPCを使用した際の動作確認にgrpcurlを使ってみた


サーバのTLS起動など

gRPCを使用する際は、平文での通信とTLSでの通信の2パターンがあります。

grpcurlの使い方も、サーバーがどちらで起動しているか?によって変わります。

この記事は文献が少なかったような気がしたので、TLSメインで書きます。

事前準備

  • ドメインの取得(テストするだけなら無料ドメインでおk)
  • 証明書の取得(テストするだけなら無料のLet's Encryptでおk)

証明書関連ファイルの用意

  • ca.crt(grpcurlなどクライアントが使う)
  • hoge.pem(サーバが使う証明書ファイル)
  • hoge.key(サーバが使う暗号キーファイル)

下記に上記の証明書一式があります。動かなくてどんな中身か?見たい場合は良いかもしれません。
https://github.com/grpc/grpc-go/tree/master/testdata

Go言語が必要なので下記からインストールする。

https://golang.org/dl/

grpcurlインストール

serverコード

package main

import (
    "context"
    "log"
    "net"

    // helloworldのサンプルでprotoファイルから生成したコードを使用
    // ソース:https://github.com/grpc/grpc-go/tree/master/examples/helloworld/helloworld
    // リフレクションの設定があるのでgRPCの動作のみ見たい場合は、消してもおkです。
    pb "grpc-sample/src/grpc/helloworld"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "google.golang.org/grpc/peer"
    "google.golang.org/grpc/reflection"
)

func main() {
    log.Println("start!!")

    var err error

    // TCPサーバ
    // tcpServer, err := net.Listen("tcp", ":443") // この指定だとtcp6になる。。
    tcpServer, err := net.Listen("tcp4", ":443")
    if err != nil {
        log.Fatalln(err)
    }

    creds, err := credentials.NewServerTLSFromFile(
        "hoge.crt",
        "hoge.key",
    )
    if err != nil {
        log.Fatalf("Failed to generate credentials %v", err)
    }

    // 複数指定予定なので、配列扱い
    opts := []grpc.ServerOption{
        grpc.Creds(creds),
    }

    grpcServer := grpc.NewServer(opts...)

    pb.RegisterGreeterServer(grpcServer, &HelloService{})

    // ※メソッドリストを表示するため必要(本番では不要)
    reflection.Register(grpcServer)

    grpcServer.Serve(tcpServer)
}

// HelloService .
type HelloService struct{}

// SayHello .
func (s *HelloService) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
    p, _ := peer.FromContext(ctx)
    response := new(pb.HelloReply)
    response.Message = req.Name + p.Addr.String()
    return response, nil
}

grpcurl

# certファイルを使ったメソッドリスト表示
$ ~/go/bin/grpcurl -cacert ca.crt example.com:443 list
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

# 証明書チェック無し(暗号化あり)でメソッドリスト表示
$ ~/go/bin/grpcurl -insecure example.com:443 list
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

# certファイルを使ったリクエスト
$ ~/go/bin/grpcurl -cacert ca.crt -d '{"name": "Morix"}' example.com:443 helloworld.Greeter/SayHello
{
  "message": "Morix ipaddress:62709"
}

# 証明書チェック無し(暗号化あり)で送るリクエスト
$ ~/go/bin/grpcurl -insecure -d '{"name": "Morix"}' example.com:443 helloworld.Greeter/SayHello
{
  "message": "Morix ipaddress:61815"
}

はまったところ

$ ~/go/bin/grpcurl -plaintext example.com:443 list
Failed to dial target host "example.com:443": context deadline exceeded

タイムアウトエラーになった。。なんでや?と思ってヘルプ見たら。

-plaintext
        Use plain-text HTTP/2 when connecting to server (no TLS).

ばっちり書いてありますね。。

暗号化状態かどうか?の確認

下記のようにしてパケットを表示しておいて通信すれば暗号化状態かどうか?確認できます。

sudo tcpdump -s0 -i eth0 -X port 443

最後に

grpcurlのおかげで疎通確認やテストがしやすくて良いですね。

ブラウザとcurlなど、ツールの豊富なhttp系プロトコル比べて、gRPCは辛かったのですがこれで開発がしやすくなりますね^^