Go言語で書くgRPC テクニック：上級編[ロードバランシングやサーバー制御]

## はじめに

gRPCは、高速・軽量な RPCフレームワークで、Go言語との相性が良く、マイクロサービス間の通信やAPIサーバーの実装に最適です。  
前回の内容よりgRPCをより高度に活用するためのテクニックを中心に、まとめてみました。

**対象読者**
- gRPCの基本・中級テクニックを理解しており、より高度な機能を使いたい方
- マイクロサービス間の通信を効率化したい方
- セキュアなgRPC通信を実現したい方

**目次**
1. gRPC Gatewayを使ったREST API化
   - gRPC Gatewayの概要
   - gRPCサービスをREST APIに変換する方法
   - OpenAPI(Swagger)ドキュメントの生成
2. gRPCのロードバランシング
   - gRPCの名前解決とロードバランサーの仕組み
   - ラウンドロビンの実装
   - Consulを使ったサービスディスカバリー
3. gRPCのセキュリティ（認証と認可）
   - SSL / TLSを使った暗号化
   - トークンベースの認証（JWT）
   - OAuth2を用いた認可

---

## 1. gRPC Gatewayを使ったREST API化

gRPC Gatewayを使うことで、gRPCサービスをREST APIとして公開することができます。

**1.1 gRPC Gatewayの概要**
- gRPCとHTTP / JSONの双方向変換を行うプロキシ。
- Protocol BuffersのコメントをOpenAPI (Swagger) ドキュメントに変換可能。
- gRPCの効率的な通信を維持しながら、RESTクライアントからも利用可能にする。

**1.2 gRPCサービスをREST APIに変換する方法**

1.protoファイルにHTTPのオプションを追加
```proto
syntax = "proto3";
package example;
import "google/api/annotations.proto";

service Greeter {
    rpc SayHello (HelloRequest) returns (HelloResponse) {
        option (google.api.http) = {
            get: "/v1/hello/{name}"
        };
    }
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}
```

2.必要なプラグインをインストール
```sh
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
```

3.gRPC Gatewayのコードを生成
```sh
protoc -I. -I$GOPATH/src \
    --go_out . --go-grpc_out . \
    --grpc-gateway_out . \
    --openapiv2_out . \
    example.proto
```

4.Gatewayのサーバーを実装
**gateway.go**
```go
mux := runtime.NewServeMux()
err := pb.RegisterGreeterHandlerServer(context.Background(), mux, &server{})
if err != nil {
    log.Fatalf("Failed to register gateway: %v", err)
}
http.ListenAndServe(":8080", mux)
```

- `grpc-gateway`がgRPCのエンドポイントをHTTP / JSONとして公開
- `GET /v1/hello/{name}`でgRPCサービス`SayHello`を呼び出せる

**1.3 OpenAPI (Swagger) ドキュメントの生成**
```sh
protoc -I. -I$GOPATH/src \
    --openapiv2_out . \
    example.proto
```
- 生成された`.swagger.json`をSwagger UIで表示可能

---

## 2. gRPC のロードバランシング

**2.1 gRPCの名前解決とロードバランサーの仕組み**
- gRPCは、ResolverとBalancerの2つのコンポーネントを使用して、ロードバランシングを行う。
- Resolver：名前解決を行う。
- Balancer：複数のサーバーに負荷を分散。

**2.2 ラウンドロビンの実装**
```go
conn, err := grpc.Dial("dns:///localhost:50051",
    grpc.WithDefaultServiceConfig(`{
        "loadBalancingConfig": [{"round_robin":{}}]
    }`),
    grpc.WithInsecure(),
)
```
- `round_robin`を指定して、ラウンドロビン方式で負荷を分散
- `dns:///`を使用してDNS ベースの名前解決を行う

**2.3 Consulを使ったサービスディスカバリー**
- `Consul`を使って**サービスディスカバリーとヘルスチェック** を実現する
- `Consul`にサービスを登録することで、動的にエンドポイントを取得する

---

## 3. gRPC のセキュリティ（認証と認可）

**3.1 SSL / TLSを使った暗号化**
- **自己署名証明書**を作成して、SSL / TLSを有効化
```go
creds, err := credentials.NewServerTLSFromFile("server-cert.pem", "server-key.pem")
s := grpc.NewServer(grpc.Creds(creds))
```
- クライアント側でも `grpc.WithTransportCredentials()` を設定して暗号化通信

**3.2 トークンベースの認証（JWT）**
- `metadata`を使用して、**JWT トークン**をヘッダーに含める
```go
md := metadata.New(map[string]string{"authorization": "Bearer <TOKEN>"})
ctx := metadata.NewOutgoingContext(context.Background(), md)
```
- サーバー側でJWTの検証を行い、認証を実施

**3.3 OAuth2 を用いた認可**
- `OAuth2`プロバイダーからアクセストークンを取得
- `OAuth2`スコープに基づいて、エンドポイントのアクセス制御を実現
- OpenID Connectを使って、**ID トークンの検証** も可能

---

## まとめ

| 項目 | 説明 |
|------|------|
| **gRPC Gateway** | gRPCをREST API化し、Swaggerドキュメントを生成 |
| **ロードバランシング** | ラウンドロビン、Consulを使ったサービスディスカバリー |
| **セキュリティ** | SSL / TLS、JWT、OAuth2による認証と認可 |

gRPC Gatewayを使ったREST API化、ロードバランシング、セキュリティ（認証と認可）など、gRPCをより高度に活用する方法を自分の知識整理も兼ねて開設しました。
gRPCマスターになりたい...