Go言語

Go と gRPC で学ぶマイクロサービス設計とデプロイガイド

ⓘ本ページはプロモーションが含まれています

スポンサードリンク

1️⃣ サービス粒度と境界の決め方

1.1 DDD と Bounded Context の基本

項目 内容
概念 Bounded Context は、ドメインモデルとその整合性を保つために「データ所有権」と「ビジネスルール」の境界を明確化する設計単位です。
利点 境界がはっきりすれば、チーム間の所有責任が分離され、変更が他サービスへ波及しにくくなります(《Domain‑Driven Design, Evans 2003》)。
実務での指標 - ユビキタス言語 が自然に切り替わる場所
- トランザクション境界 が跨がらないこと
- データ更新頻度 が大きく異なる領域

1.2 サービス例:User と Order

項目 User Service Order Service
主なエンティティ User, Profile, Credential Order, Cart, Payment
データストア PostgreSQL(認証情報) MySQL(取引履歴)+Redis(カート)
主要 API CreateUser, GetProfile PlaceOrder, CancelOrder
所有チーム AuthTeam OrderTeam
境界根拠 認可ロジックは ユーザー単位 に集中させ、注文フローは在庫・決済と独立させることで相互依存を排除

ポイント:サービス粒度は「ビジネス機能の独立性」だけでなく、「データ所有権」と「チーム責任」の分離でも測ります。


2️⃣ Protocol Buffers と gRPC の基礎

2.1 .proto ファイル設計のベストプラクティス

項目 推奨
syntax proto3(非推奨な required/optional が無く、将来拡張しやすい)
パッケージ yourdomain.service.v1 のようにバージョンを明示
go_package オプション "github.com/yourorg/project/internal/<pkg>;pb" で名前空間衝突防止
フィールド番号 1 〜 15 はタグが 1 バイト に収まります((field_number << 3) | wire_type が 0x08‑0x7F)。16 以上は 2 バイト 必要になるため、将来追加分は 16 以降に割り当てると、既存メッセージのバイナリサイズ増加を抑制できます。
※公式ドキュメント: Encoding – Protocol Buffers(Google)
コメント // コメントは protoc-gen-doc で自動生成できるので必ず書く

フィールド番号とサイズ増加の具体例

  • idname のタグは 1 バイト
  • description2 バイト(0x82, 0x01)になるため、同じペイロード長でもメッセージ全体が 1 バイト多く なります。大量レコードでこの差が積み重なると、ネットワーク帯域やストレージに実質的なコスト増となります(Google のベンチマークで 10 % 程度のサイズ増加が確認されています)。

2.2 gRPC サーバ/クライアント実装の要点

項目 推奨
Context の受け渡し CreateUser(ctx context.Context, req *pb.CreateUserRequest) のように必ず context を受け取り、タイムアウト・キャンセルを伝搬
エラーハンドリング status.Errorf(codes.Internal, "...") で gRPC 標準ステータスコードを返す。クライアント側は status.FromError(err) でコード取得しリトライロジックに活用
バリデーション proto に必須項目が無いので、サーバ側で入力検証(例: email 正規表現)を実装
oneof の利用 複数フォーマットの互換性確保に便利。例: oneof contact { string email = 2; string phone = 3; }

サーバ側サンプル(User Service)

クライアント側サンプル


3️⃣ Go プロジェクトの構造とモジュール管理

3.1 推奨ディレクトリレイアウト

  • internalモジュール境界 をコンパイル時に強制し、意図しない依存を防止します(公式 Go 設計ガイド参照)。
  • cmd/server/main.go は設定ロード・サーバ起動だけに留め、ロジックはすべて internal/* に委譲。

3.2 モジュールと依存関係

go mod tidy により未使用の依存は自動除去、CI では actions/cache を活用してビルド時間を約30 %短縮できます。


4️⃣ Docker コンテナ化とマルチステージビルド

4.1 軽量イメージ作成のベストプラクティス

ステップ 内容
Build Stage golang:1.22-alpine → ソース取得、buf generate、静的リンクビルド(CGO_ENABLED=0
Runtime Stage gcr.io/distroless/static:nonroot または scratch → ビルド成果物だけをコピー
レイヤーキャッシュ活用 go.mod/go.sum を最初にコピーし、依存変更が無い限り再ビルドを回避

完全サンプル Dockerfile

  • サイズdistroless/static は約 9 MB、scratch なら 5 MB 程度に収まります。
  • セキュリティ:glibc が無いため攻撃面が大幅に縮小。

5️⃣ ローカル開発環境と本番デプロイ

5.1 docker‑compose によるローカルマルチサービス構成

  • depends_on起動順序 のみ保証します。実運用では各コンテナに healthcheck を追加し、依存サービスが正常になるまで待機させます。

5.2 Kubernetes Manifest(Production 用)

deployment.yaml

service.yaml

configmap.yaml

  • ポイントreadinessProbe に gRPC ヘルスチェックを設定し、Pod が正常になるまでトラフィックを受け付けません。
  • 機密情報は Secret に分離し、envFrom.secretRef で注入します。

6️⃣ CI/CD パイプラインと Observability

6.1 GitHub Actions(テスト・ビルド・デプロイ)

  • buf generate を CI に組み込むことで proto 変更とコード生成の不整合 を防止。
  • actions/cache がモジュールキャッシュを共有し、ビルド時間を約30 %短縮。

6.2 OpenTelemetry による可観測性

初期化(Tracer Provider)

  • Collector → Jaeger / Prometheus にエクスポートすれば、トレース遅延は 5 ms 未満に抑えられます(Istio + OpenTelemetry の実績参照)。
  • gRPC サーバでは otelgrpc.UnaryServerInterceptor をミドルウェアとして登録し、全 RPC が自動的に計測されます。

6.3 セキュリティ:mTLS と JWT

TLS 設定と認可インターセプタ

  • mTLS により通信路が暗号化され、相互認証でサービス間の信頼性を確保。
  • JWT はリクエスト単位の認可情報(ロール等)を提供し、インターセプタで一元管理できるため RBAC が容易になる。

7️⃣ まとめと次のアクション

フェーズ 主な作業
設計 DDD の Bounded Context を基にサービス境界を決定(User / Order)
スキーマ .proto 作成 → buf generate で Go コード生成、フィールド番号は 1‑15 に抑える
実装 Go モジュール構造 (cmd/, internal/, pkg/) → gRPC ハンドラ・クライアント実装、Context とステータスコード活用
コンテナ化 マルチステージ Dockerfile(distroless)で 10 MB 未満のイメージを作成
デプロイ docker‑compose(ローカル)、Kubernetes Manifest(本番)でローリングアップデート
CI/CD GitHub Actions → テスト・コード生成・Docker ビルド・K8s デプロイ
観測性 OpenTelemetry SDK + Collector → Jaeger / Prometheus
セキュリティ mTLS + JWT インターセプタで暗号化・認可を統合

行動チェックリスト

  • [ ] リポジトリをクローン git clone https://github.com/yourorg/go-microservice-sample.git
  • [ ] buf generate で proto コード生成、エラーが無いことを確認
  • [ ] go test ./... がすべて成功するかローカルで実行
  • [ ] docker compose up -d で User/Order サービスと DB が起動できるか検証
  • [ ] Kubernetes へデプロイ kubectl apply -k k8s/overlays/staging
  • [ ] GitHub Actions が自動ビルド・プッシュし、kubectl set image が正しく実行されることを確認
  • [ ] Jaeger UI と Prometheus のメトリクスが取得できているかブラウザでチェック
  • [ ] curl -v https://usersvc:50051 などで mTLS が機能し、JWT 認証が通過するエンドツーエンドテストを実施

これらの手順を完了すれば、Go + gRPC + Protocol Buffers による本格的なマイクロサービス基盤が構築できます。ビジネス要件に合わせてサービスを増減させながら、上記ベストプラクティスを継続的に適用していくことが、長期的な保守性と拡張性の鍵となります。


本稿は執筆時点(2024 年)で確認できた公開情報に基づいています。将来的に公式ドキュメントやツールのバージョンが更新された場合は、適宜内容を見直してください。

スポンサードリンク

-Go言語
-, , , , , , , , ,