Contents
- 1 対象読者・前提と短い実行手順(Goでマイクロサービスを作るための準備)
- 2 設計とプロジェクト構成(Bounded Context・パッケージ設計・フレームワーク選定)
- 3 通信プロトコルとインターフェース設計:REST, gRPC と Protocol Buffers 運用
- 4 ハンズオン:最小サンプルサービスの実装とテスト
- 5 Docker化とKubernetesデプロイ(安全で軽量な Dockerfile とマニフェストの実務例)
- 6 CI/CD(実運用上の注意点:キャッシュ、署名、SBOM)
- 7 観測性:ログ・メトリクス・トレース・プロファイリング
- 8 セキュリティとデータ整合性パターン
- 9 信頼性パターンと運用(リトライ・サーキットブレーカー・Bulkhead 等)
- 10 用語集(表記の統一)
- 11 まとめ(要点の整理)
- 12 参考リソース(公式ドキュメント中心)
対象読者・前提と短い実行手順(Goでマイクロサービスを作るための準備)
ここではこの記事の想定読者と動作前提を明示します。開発をすぐ始めたい人向けに、実行手順の要約も載せます。
対象読者
想定読者を明確にしておくと、記事中の推奨レベルが理解しやすくなります。ここでは中級エンジニアを主対象としています。
- Goの基礎(文法・モジュール)が分かる中級者向け。
- Docker・Kubernetesの基本操作ができることを前提。
- 初心者には補足ポイント、上級者には実運用上の注意点も示します。
短い実行手順(要約)
素早く動かしたい場合の最短ステップを示します。詳細は本文で補足します。
- リポジトリをクローンして Go モジュールを復元する。
- buf/protoc で proto を生成する(CIで固定)。
- go build でバイナリを生成し Docker イメージを作る。
- ローカルで docker run または KinD にデプロイして動作確認する。
- CIでイメージのスキャン・SBOM生成・署名を行い、GitOpsで本番へ展開する。
設計とプロジェクト構成(Bounded Context・パッケージ設計・フレームワーク選定)
マイクロサービスはドメイン設計とコード構成が運用しやすさを左右します。ここでは境界の切り方と、Goプロジェクトの実務向け構成、依存注入の考え方を示します。
Bounded Context によるサービス分割基準
サービス分割はビジネス観点と運用観点の両方で判断します。分割が不適切だと依存と運用コストが増えます。
- ビジネス能力単位で変化が独立するかを基準にする。
- データ所有者が明確で、スキーマ変更がサービス単位で可能か。
- チームの所有範囲(チーム境界)とデプロイ単位に合致しているか。
- トランザクション境界が大きすぎないか(2PCの回避等)。
推奨プロジェクト構成(サンプル)
下記は実務で扱いやすいディレクトリ構成の一例です。test、CI、migrations 等を明確に分けます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
. ├── api/ # OpenAPI / proto ├── cmd/ │ └── service/ │ └── main.go ├── internal/ │ ├── domain/ │ ├── service/ │ ├── repository/ │ └── transport/ # http/grpc handlers ├── pkg/ # 再利用可能な公開パッケージ ├── migrations/ ├── configs/ ├── deployments/ # k8s manifests / helm ├── Dockerfile ├── Makefile └── test/ |
依存注入とフレームワーク選定
依存注入はコンストラクタ注入を基本とし、過度な抽象化を避けます。小規模は net/http や chi、中規模以上で gRPC や go-kit/Kratos を検討します。
- コンストラクタ注入でテスト容易性を確保する。
- 部分的に wire や fx を使うが、フレームワークの導入コストを評価する。
- HTTP: net/http / chi / gin。内部RPC: gRPC(grpc-go)。
通信プロトコルとインターフェース設計:REST, gRPC と Protocol Buffers 運用
インターフェースは用途に合わせて選びます。ここでは選定基準と、Protocol Buffers の生成運用(バージョン固定・CI組み込み)を示します。
REST と gRPC の比較(選定基準)
用途別に向き・不向きを整理しました。選定は公開先や性能要件で判断します。
| 比較項目 | REST (HTTP/JSON) | gRPC (Protobuf) |
|---|---|---|
| ブラウザ互換性 | 高い | そのままでは低い(gRPC-Web が必要) |
| デバッグ性 | JSONで可視化しやすい | バイナリだが型安全 |
| 性能 | 十分なケースが多い | 低レイテンシ・高効率 |
| ストリーミング | 制限あり | 標準サポート |
| 契約管理 | OpenAPI | Protobuf(厳密) |
Protocol Buffers と生成ワークフロー(protoc / buf)
Proto の生成は CI でバージョンを固定し、自動化します。buf を用いる運用が推奨されます。
- protoc と各プラグイン(protoc-gen-go, protoc-gen-go-grpc, grpc-gateway 等)はバージョン固定する。
- buf を使うと lint、breaking check、generate を一元管理できる。buf.lock でバージョン固定が可能。
- tools.go(ビルドタグ)や //go:generate を使ってローカル開発で揃える運用にする。
例: tools.go の抜粋
|
1 2 3 4 5 6 7 8 9 10 11 12 |
//go:build tools // +build tools package tools import ( _ "google.golang.org/protobuf/cmd/protoc-gen-go" _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" _ "github.com/bufbuild/buf/cmd/buf" ) |
CI 例(buf を使う場合):
- buf lint
- buf breaking --against 'origin/main'
- buf generate
- go vet / golangci-lint / go test
バージョン互換性の注意点: protoc 本体とプラグインの互換性を確認し、CIで明示的にバージョンをインストールすること。
ハンズオン:最小サンプルサービスの実装とテスト
実際に動くミニマムな実装フローとテスト戦略を示します。段階的に進めることで品質を確保します。
実装のステップ(順序付き)
以下の順で実装すると後工程が楽になります。
- ドメインモデルを定義する(internal/domain)。
- リポジトリインターフェースを宣言する(interface-driven)。
- DB 実装やインメモリを作る(テスト用の差替え可能に)。
- HTTP ハンドラ(chi 等)/gRPC サーバを実装する。
- Context とタイムアウトポリシーを全層で統一する。
- Graceful shutdown、プローブ、メトリクス、トレースを組み込む。
テスト戦略とローカル検証
テストは層ごとに分け、CIで順序実行します。
- ユニットテスト:テーブル駆動、mock を利用(mockgen, testify)。
- 統合テスト:testcontainers-go で DB 等を起動して実行。
- 契約テスト:buf/pact 等で API 契約を検証。
- E2E:KinD 等で最小 k8s クラスタへデプロイして確認。
サンプルリポジトリの用意(推奨)
クローンしてすぐ動く最小実装を用意すると導入が早まります。推奨ファイル群:
- cmd/service/main.go(起動エントリ)
- api/proto/*.proto(API 仕様)
- internal/{domain,service,repository,transport}/(実装)
- Dockerfile, Makefile, .github/workflows/ci.yml, k8s/manifests/
リポジトリ名例: github.com/
Docker化とKubernetesデプロイ(安全で軽量な Dockerfile とマニフェストの実務例)
イメージの最小化とセキュリティ、Kubernetes 側での最小権限設計が重要です。特に CA 証明書と CGO の扱いは本番でのトラブル要因になります。
推奨 Dockerfile(CA 証明書と CGO の注意)
CGO を無効化して静的にビルドすると最終イメージを小さくできますが、CGO を必要とするライブラリがある場合は使えません。以下は静的ビルド+distroless に CA 証明書をコピーする例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# builder FROM golang:1.20-bullseye AS builder WORKDIR /src RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* ENV CGO_ENABLED=0 GOOS=linux GOARCH=amd64 COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -ldflags="-s -w" -o /app ./cmd/service # final FROM gcr.io/distroless/static:nonroot COPY --from=builder /app /app # CA 証明書をコピー(distroless に証明書が含まれない場合の対策) COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ USER nonroot EXPOSE 8080 ENTRYPOINT ["/app"] |
CGO の副作用と代替:
- CGO_ENABLED=0 にすると一部のネイティブ依存ライブラリ(例:SQLite の github.com/mattn/go-sqlite3 等)が動作しません。
- CGO が必要な場合は glibc ベースの final イメージ(gcr.io/distroless/cc:nonroot や debian slim を利用)を検討する。
Kubernetes マニフェストと最小権限 RBAC / NetworkPolicy
Deployment で serviceAccountName を使う場合、対応する最小権限 Role/RoleBinding を用意します。また NetworkPolicy で Pod間の通信を制限します。
ServiceAccount / Role / RoleBinding(最小例):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
apiVersion: v1 kind: ServiceAccount metadata: name: sample-svc-sa namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: sample-svc-role namespace: default rules: - apiGroups: [""] resources: ["pods","services"] verbs: ["get","list","watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: sample-svc-rb namespace: default subjects: - kind: ServiceAccount name: sample-svc-sa roleRef: kind: Role name: sample-svc-role apiGroup: rbac.authorization.k8s.io |
NetworkPolicy(同一ネームスペースの特定ラベルのみ許可する例):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-from-app-frontend namespace: default spec: podSelector: matchLabels: app: sample-svc policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: role: frontend |
プローブ、リソース制限、securityContext(非root)などは必ず設定してください。
CI/CD(実運用上の注意点:キャッシュ、署名、SBOM)
CI は単純な流水線だけでなく、キャッシュ、並列化、秘密鍵管理、SBOM の生成といった実運用の課題に対応する必要があります。
CI 最適化とキャッシュ戦略
CI のボトルネックを減らすため、ビルドキャッシュと分割を行います。
- Go モジュールキャッシュ: actions/cache で ~/.cache/go-build と GOPATH/pkg/mod をキャッシュする。
- Docker Buildx: cache-from / cache-to(registry もしくは GitHub Actions キャッシュ)を使う。
- テスト分割: ユニットはプルリクで高速に回し、統合テストは重いジョブで並列または別ジョブにする。
簡易的な GitHub Actions のキャッシュ例(抜粋):
|
1 2 3 4 5 6 7 8 9 |
- name: Cache Go modules uses: actions/cache@v4 with: path: | ~/.cache/go-build ~/.cache/go-test $GITHUB_WORKSPACE/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} |
イメージ署名と鍵管理(cosign と KMS)
イメージ署名は信頼チェーン構築に重要です。鍵はリポジトリに置かず KMS を使います。
- cosign を利用してイメージに署名する(GCP KMS / AWS KMS / Azure Key Vault と連携可能)。
- GitHub Actions の OIDC を使い短期クレデンシャルでレジストリにログインする。
署名の概念例(詳細は cosign ドキュメント参照):
- cosign sign --key gcpkms://projects/.../cryptoKeys/... $IMAGE
SBOM とスキャン(syft / trivy 等)
- syft で SBOM を生成(JSON/CycloneDX)。
- trivy 等で脆弱性スキャンを行い、CIで閾値超過時にブロックする。
例:
|
1 2 3 |
syft $IMAGE -o json > sbom.json trivy image --format json --output trivy-report.json $IMAGE |
鍵は KMS で管理し、CI のログに平文を残さないことが重要です。
観測性:ログ・メトリクス・トレース・プロファイリング
ログ・メトリクス・トレースを揃えることが運用上の最重要事項です。さらにプロファイリングは本番では慎重に扱います。
ログ(構造化ログとトレースID)
構造化ログを採用し、必ずトレースIDをログに含めます。zap や zerolog を推奨します。
- JSON フォーマットで出力し、 Fluent Bit / Fluentd で集約。
- trace_id をコンテキストから取得してログに埋めるルールを定める。
メトリクス(Prometheus)
Prometheus 用メトリクスを用意し、ヒストグラムやサマリでレイテンシを計測します。
- prometheus/client_golang を使い、エンドポイント /metrics を公開。
- ラベルの cardinality を抑える設計(高基底ラベルを避ける)。
トレース(OpenTelemetry と OTLP)
トレースは依存関係で発生する遅延の特定に有効です。OTLP 経由で collector に集約します。
- go.opentelemetry.io/otel を導入し、OTLP exporter を設定。
- サンプリング方針はサービスの負荷と SLO に合わせて調整する。
pprof(本番での安全な扱い)
pprof によるプロファイリングは重要ですが、本番公開は危険です。公開方法には注意が必要です。
- 本番で /debug/pprof をインターネット公開しない。
- localhost バインド、内部ネットワーク限定、認証付き、あるいは一時的に有効化する運用にする。
- k8s では debug 用ポッドに port-forward するか、管理専用のサイドカーで pprof を隔離する。
セキュリティとデータ整合性パターン
認証・認可、シークレット管理、分散トランザクションの対策を適切に組み合わせます。Outbox や Saga は整合性維持の代表的パターンです。
認証・認可とサービス間セキュリティ
- 外部向けは API Gateway に OIDC/OAuth2 を委譲する。
- サービス間は mTLS を推奨(サービスメッシュや cert-manager を利用)。
シークレット管理
- Kubernetes Secret を直接コミットしない。Vault / ExternalSecrets / SealedSecrets 等で管理し、キーは KMS で保護する。
- シークレットのローテーション手順を定義する。
データ整合性:Outbox と Saga の概要
Outbox と Saga は分散データ整合性に使われる主要パターンです。設計とオペレーションの注意点を押さえます。
- Outbox: アプリの DB トランザクション内でイベントを outbox テーブルに永続化。外部 dispatcher が outbox を読み取りメッセージブローカーに転送することで整合性を担保する。
- Saga: 複数サービスの補償操作を定義することで分散トランザクションを回避する(オーケストレーション型/コレオグラフィ型)。
Outbox テーブル例:
|
1 2 3 4 5 6 7 8 9 |
CREATE TABLE outbox ( id UUID PRIMARY KEY, aggregate_id UUID, event_type TEXT, payload JSONB, status TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() ); |
非同期連携の実装上の注意
- 冪等性(idempotency key)を必須にする。
- DLQ とリトライ方針を明確化する。
- コンシューマ側の処理はステートレスかつ再実行可能に設計する。
信頼性パターンと運用(リトライ・サーキットブレーカー・Bulkhead 等)
障害波及を抑えるためのパターンとトラブルシューティングの基本フローを示します。
リトライ・バックオフ・サーキットブレーカー
- リトライは指数バックオフ+ジッターを使う。ライブラリ例: cenkalti/backoff。
- サーキットブレーカーでフォールトドメインを隔離(sony/gobreaker 等)。
- Bulkhead(リソース分離)で同一障害が全体を巻き込まないようにする。
監視・アラート設計(SLO とエラーバジェット)
- SLO をサービスごとに設定し、アラートはエラーバジェットに基づいて設計する。
- アラートはノイズを避けるために複数の指標(エラーレート、p99 レイテンシ、リソース枯渇)で構成する。
用語集(表記の統一)
用語と略称を統一すると読者の混乱を減らせます。以下はこの記事内での表記方針です。
- gRPC:gRPC(grpc-go は Go 向け公式実装を指す)
- Protocol Buffers:Protocol Buffers(proto / Protobuf)
- grpc-gateway:grpc-gateway(gRPC→HTTP/JSON ブリッジ)
- OTLP:OpenTelemetry Protocol(トレース/メトリクス輸送プロトコル)
- HPA:Horizontal Pod Autoscaler(Kubernetes の自動スケール機能)
- Outbox:アプリ DB 内にイベントを永続化するパターン(配信の信頼性向上)
必要に応じてプロジェクト内に同様の用語集を README に置くことを推奨します。
まとめ(要点の整理)
最後にこの記事の要点を簡潔に箇条書きでまとめます。導入から運用までの主要な注意点を再確認してください。
要点まとめ
- 設計はドメイン(Bounded Context)とチーム組織に合わせて行う。
- Protocol 選定は公開先と性能要件で判断し、Protobuf を CI でバージョン固定する。
- Docker イメージは最小化するが、CA 証明書のコピーや CGO の有無に注意する(必要なら glibc ベースを使用)。
- Kubernetes では最小権限 RBAC と NetworkPolicy を必ず設定する。
- CI はキャッシュ、SBOM、イメージ署名(KMS)を組み込み、鍵は絶対にレポジトリに置かない。
- 観測性はログ・メトリクス・トレースを揃え、pprof は本番で直接公開しない運用にする。
- データ整合性は Outbox / Saga 等のパターンで設計し、冪等性・DLQ を整備する。
参考リソース(公式ドキュメント中心)
以下は信頼できる公式ドキュメントや主要ツールのページです。詳細実装は各公式ドキュメントを参照してください。
- Go(公式ドキュメント):https://go.dev/doc/
- gRPC(公式):https://grpc.io/docs/
- Protocol Buffers(公式):https://developers.google.com/protocol-buffers
- buf(プロト管理ツール):https://buf.build/
- Kubernetes(公式ドキュメント):https://kubernetes.io/docs/
- Prometheus(公式):https://prometheus.io/docs/introduction/overview/
- OpenTelemetry(公式):https://opentelemetry.io/
- sigstore / cosign(イメージ署名):https://docs.sigstore.dev/cosign/
- syft(SBOM 生成):https://github.com/anchore/syft
- trivy(脆弱性スキャン):https://aquasecurity.github.io/trivy/
- testcontainers-go(統合テスト用):https://github.com/testcontainers/testcontainers-go
(上記を参考に、チームのポリシーに合わせてバージョン固定・CI統合・サンプルリポジトリの整備を行ってください。)