Contents
対象読者と前提・開発環境
このセクションでは、想定する読者層と最低限の前提環境を整理します。準備が整っていればハンズオンがスムーズに進みます。
対象読者
対象読者の想定を明確にします。想定外の場合は適宜調整してください。
- 中級〜上級のバックエンドエンジニア、SRE
- Go のモジュール、goroutine、context、HTTP/SQL の基礎知識がある方
推奨 Go バージョンと基本ツール
推奨バージョンと必須ツールを示します。ツールはプロジェクトで版固定することを強く推奨します。
- Go 1.20 以上を推奨。可能なら最新の安定版に合わせます。
- 必須ツール例:git、docker (BuildKit 有効推奨)、docker compose (CLI v2)、kubectl、kind/k3d、Helm/Kustomize、protoc/buf、oapi-codegen、golangci-lint、Make、goreleaser、trivy、cosign
環境チェック(コマンド例)
環境が整っているかを簡易チェックします。各コマンドはローカルで実行して確認してください。
|
1 2 3 4 5 6 |
go version git --version docker --version docker compose version kubectl version --client |
設計:マイクロサービスの境界と API 契約管理
サービス設計とスキーマ管理の方針は後工程の運用コストに直結します。ここでは境界設計と API の選択基準、スキーマ CI の運用を示します。
境界設計と同期/非同期の判断
境界はドメイン固有の責務で決めます。同期と非同期の使い分け基準を例示します。
- 同期通信が向くケースは低レイテンシで即時応答が必要な操作です。たとえば認証や決済承認などが該当します。
- 非同期はバックグラウンド処理や高スループットが求められる処理に向きます。重い集計やメール配信などが例です。
- 非同期運用では Outbox パターンや SAGA を検討し、イベントは冪等に設計します。
REST と gRPC の使い分け、契約の運用
REST と gRPC の特性を踏まえた選択と、契約管理の実務運用を示します。
- 外部公開 API は互換性の観点から OpenAPI(REST)を選ぶことが多いです。
- 内部サービス間は型安全で高速な gRPC を選ぶケースが多いです。
- Protobuf や OpenAPI はスキーマを単一ソースにして CI で自動チェックします。
スキーマ管理と CI 自動化(実例コマンド)
スキーマ生成や breaking check を CI に組み込みます。差分検出を忘れないでください。
- Protobuf 生成(buf 推奨):
|
1 2 3 |
buf generate buf breaking --against 'buf.build/yourorg/yourrepo:main' |
- OpenAPI からの生成(oapi-codegen は -o を使う):
|
1 2 |
oapi-codegen -package api -generate types,server -o pkg/api/openapi_gen.go api/openapi.yaml |
- CI での生成差分チェック例:
|
1 2 3 |
make generate git diff --exit-code -- pkg/api/openapi_gen.go || (echo "generated files differ"; exit 1) |
生成は CI で実行し、差分があれば PR を失敗させることで手動コミット漏れを防ぎます。
プロジェクト構成・依存管理・データアクセス
保守性の高いリポジトリ構成と、DB・マイグレーション運用のポイントを示します。依存の再現性を重視してください。
リポジトリ構成と依存管理
推奨レイアウトの一例とモジュール運用方針を示します。大規模化に備えて可搬性を意識します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
. ├── cmd/ │ └── service/ │ └── main.go ├── internal/ │ ├── domain/ │ ├── service/ │ └── transport/ ├── pkg/ ├── api/ │ ├── proto/ │ └── openapi.yaml ├── migrations/ ├── deployments/ │ ├── k8s/ │ └── helm/ ├── .github/workflows/ ├── Dockerfile ├── Makefile └── go.mod |
- go mod は CI とローカルで同じコマンドを実行します(go mod tidy 等)。
- オフライン再現が必要なら vendor を利用して go mod vendor を行います。
DB アクセスとマイグレーション
DB 接続やマイグレーションの運用方針を明示します。ツールはバージョン固定でインストールします。
- 推奨ライブラリ: sqlx、Ent、GORM(用途に応じて選定)
- マイグレーション: golang-migrate を CI で実行するか運用手順に組み込みます
- migrate のバージョン固定例(Makefile):
|
1 2 3 4 5 |
# Makefile target install-tools: go install github.com/golang-migrate/migrate/v4/cmd/migrate@v4.15.2 go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.9.10 |
DB 接続プールのチューニングと検証
接続数の計算方法と検証手順を示します。実ワークロードで検証することが必須です。
- 基本設定(database/sql):
|
1 2 3 4 5 |
db.SetMaxOpenConns(50) db.SetMaxIdleConns(25) db.SetConnMaxIdleTime(5 * time.Minute) db.SetConnMaxLifetime(30 * time.Minute) |
- 接続数算出例: DB 側の max_connections = 500、運用で確保する余裕 = 50、インスタンス数 = 10 の場合
- アプリ側最大接続数 = floor((500 - 50) / 10) = 45
- 検証方法: k6 や vegeta で負荷試験を行い、DB の max_connections、待ち時間、エラー率を観察します。
ローカル開発フロー、コンテナ化、CI/CD の実践
ローカルでの高速ループから CI での再現性まで、具体的な手順と実務的改善点を示します。Compose のバージョン依存に注意してください。
ローカル開発とホットリロード
ローカルの素早いフィードバックループを作る方法を示します。devcontainer の利用も推奨します。
- 単純起動:
|
1 2 |
go run ./cmd/service |
- ホットリロード: air、CompileDaemon などを利用します。devcontainer を用いればチームで環境を統一できます。
docker compose(Compose CLI v2)で依存サービスを起動
docker-compose 表記は古く、現在は docker compose(ハイフン無し)の CLI v2 を推奨します。以下は例です。
- docker compose ファイル(例):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
version: "3.8" services: db: image: postgres:15 environment: POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - db-data:/var/lib/postgresql/data service: build: . environment: DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@db:5432/app?sslmode=disable ports: - "8080:8080" depends_on: - db volumes: db-data: |
- 起動コマンド(Compose v2 CLI):
|
1 2 3 |
cp .env.example .env # .env を .gitignore にする docker compose up --build -d |
- 注意点: docker compose は v2(docker cli のサブコマンド)と v1(docker-compose バイナリ)で挙動が異なる場合があります。ドキュメントや CI ランナーの環境に合わせて明記してください。
Dockerfile と Distroless の運用注意
Distroless を使う場合の制約とデバッグ時の対処法を示します。CGO が必要な依存は特に注意が必要です。
- ポイント:
- Distroless はシェルを持たずデバッグが難しいです。
- CGO を無効化できないライブラリがある場合、静的リンクができず distroless が使えないことがあります。
-
CGO 必要時は glibc を含むベースイメージ(debian-slim など)を最終イメージにするか、musl 静的ビルドを検討します。
-
マルチステージ Dockerfile(Distroless + debug イメージ):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# builder FROM golang:1.20-bullseye AS builder WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app ./cmd/service # distroless final FROM gcr.io/distroless/static COPY --from=builder /app /usr/local/bin/service USER 65532:65532 ENTRYPOINT ["/usr/local/bin/service"] # debug image (optional) FROM debian:bookworm-slim AS debug COPY --from=builder /app /usr/local/bin/service RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl procps && rm -rf /var/lib/apt/lists/* USER 65532:65532 ENTRYPOINT ["/usr/local/bin/service"] |
- 運用方針:
- 本番は distroless を使い、デバッグ用に debug イメージを別途用意します。
- 依存で CGO が必須なら最終イメージを debian-slim のような glibc ベースにします。
CI の実務改善点(GitHub Actions 例)
CI での高速化と再現性向上の実務ポイントを示します。キャッシュや buildx、OIDC を活用します。
- 重要事項: モジュールキャッシュ、ビルドキャッシュ、レジストリ認証は CI で明示的に扱います。
- 簡易ワークフロー(抜粋):
|
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 30 31 32 33 34 35 36 37 38 39 40 |
name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: 1.20 - name: Cache Go build uses: actions/cache@v4 with: path: | ~/.cache/go-build ${{ env.GOMODCACHE }} key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - run: go mod download - run: golangci-lint run ./... - run: go test ./... -v - name: Set up QEMU and Buildx uses: docker/setup-buildx-action@v2 - name: Login to registry (OIDC) uses: docker/login-action@v2 with: registry: ghcr.io oidc: true - name: Build and push multi-arch image uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max - name: Scan image run: trivy image --severity HIGH,CRITICAL ghcr.io/${{ github.repository }}:${{ github.sha }} - name: Sign image run: cosign sign --key ${{ secrets.COSIGN_KEY }} ghcr.io/${{ github.repository }}:${{ github.sha }} |
- 補足:
- OIDC を使えば長期的なシークレットを CI に置かずに済みます。
- buildx のキャッシュを活用するとレイヤー再利用で時間短縮できます。
- test 用コンテナは job 内で docker compose または service コンテナを使い、起動待ち(wait-for)を明示します。
シークレット管理と安全な運用
ローカルと CI/本番での安全なシークレット運用パターンを示します。リポジトリに機密を置かないことが最重要です。
- ローカル: .env.example を用意し、実環境の .env は .gitignore に登録します。direnv、sops、git-crypt、pass などで管理します。
- CI: GitHub Secrets、GitHub OIDC、または外部 Secret Manager(GCP Secret Manager、AWS Secrets Manager 等)を利用します。
- Kubernetes 本番: ExternalSecrets(ExternalSecrets Operator)や HashiCorp Vault、SealedSecrets を推奨します。Kubernetes Secret は base64 なので暗号化・KMS 管理を行ってください。
Kubernetes へのデプロイと運用・可観測性
Kubernetes での実装例と、可観測性・安全性の実務的な優先順序を示します。マニフェスト名と操作コマンドは一致させます。
Deployment / Service / Ingress の例(名前整合)
Deployment 名と Service 名が一致していない例を修正し、実行コマンドと整合させます。以下は最小例です。
|
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
apiVersion: apps/v1 kind: Deployment metadata: name: svc-deployment spec: replicas: 2 selector: matchLabels: app: svc template: metadata: labels: app: svc spec: containers: - name: svc image: ghcr.io/yourorg/service:latest ports: - containerPort: 8080 - name: admin containerPort: 6060 readinessProbe: httpGet: path: /health/ready port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /health/live port: 8080 initialDelaySeconds: 15 periodSeconds: 20 resources: requests: cpu: "100m" memory: "200Mi" limits: cpu: "500m" memory: "512Mi" envFrom: - configMapRef: name: svc-config - secretRef: name: svc-secret --- apiVersion: v1 kind: Service metadata: name: svc-service spec: selector: app: svc ports: - name: http port: 80 targetPort: 8080 - name: admin port: 6060 targetPort: 6060 |
- 運用コマンド例:
|
1 2 3 4 5 |
kubectl apply -f deployments/k8s/ kubectl rollout status deployment/svc-deployment kubectl port-forward svc/svc-service 8080:80 curl http://localhost:8080/health/ready |
可観測性の優先実装順序(簡潔)
可観測性は段階的に導入します。優先度を付けて実施してください。
- 構造化ログ(JSON)と集約パイプライン
- 基本メトリクス(Prometheus / /metrics)
- アラートの設定(重要な SLO に基づく)
- 分散トレーシング(OpenTelemetry → Jaeger/Tempo)
- プロファイリング(pprof)は最後に導入し、安全に公開する
pprof の安全な利用方法
pprof は強力ですが公開は危険です。安全に使う手順を示します。
- 本番で直接公開しない。管理用ポートを内部のみにバインドするか、認証を付加します。
- 一時的な解析は port-forward を使うのが推奨です。
|
1 2 3 |
kubectl port-forward deployment/svc-deployment 6060:6060 go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30 |
- 本番で公開する場合は mTLS、IP 制限、Basic/Digest 認証または網内のみのネットワークに限定してください。
グレースフルシャットダウンとライフサイクル管理(Go 実装例)
SIGTERM 受信で正常にドレインする実装は必須です。実例を示します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
srv := &http.Server{Addr: ":8080", Handler: handler} go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal(err) } }() stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() _ = srv.Shutdown(ctx) |
- SIGTERM 受信時は readiness を false にして接続をドレインします。
実践ハンズオン:サンプル実装・チェックリスト・参考資料
実例リポジトリを使ったハンズオン手順と本番前チェックリスト、ツールの固定化方法を示します。再現可能な公開リポジトリを参照してください。
ハンズオン手順(実例リポジトリを使った流れ)
このハンズオンでは公開リポジトリを例に手順を示します。手元で動かす前にリポジトリの README を必ず確認してください。例として Ardan Labs のサンプルを参照します。
- クローン(例):
|
1 2 3 |
git clone https://github.com/ardanlabs/service.git cd service |
- ローカルビルドと実行:
|
1 2 3 4 5 |
go mod download go run ./cmd/service # または make run |
- 依存サービスを docker compose で起動:
|
1 2 3 |
cp .env.example .env docker compose up --build -d |
- マイグレーション実行(バージョン固定された migrate を使用):
|
1 2 |
migrate -path ./migrations -database "$DATABASE_URL" up |
- ローカルでのイメージビルド/検証:
|
1 2 3 |
docker buildx build --platform linux/amd64 -t ghcr.io/yourorg/service:local --load . docker run --rm -e DATABASE_URL=$DATABASE_URL -p 8080:8080 ghcr.io/yourorg/service:local |
- CI 内での生成差分チェック(例):
|
1 2 3 |
make generate git diff --exit-code || (echo "Please run make generate and commit changes"; exit 1) |
- Kind/k3d へデプロイと動作確認:
|
1 2 3 4 5 6 |
kind create cluster kubectl apply -f deployments/k8s/ kubectl rollout status deployment/svc-deployment kubectl port-forward svc/svc-service 8080:80 curl http://localhost:8080/health/ready |
本番前チェックリスト(要点まとめ)
本番投入前に確認すべき項目を列挙します。運用ルールに合わせてチェックを自動化してください。
- TLS(Ingress / LB)で TLS 終端が正しく構成されていること
- シークレットは Vault/Secret Manager/ExternalSecrets で管理していること
- イメージが署名され、脆弱性スキャンで重大な脆弱性がないこと
- readiness/liveness probe が適切に設定されていること
- requests/limits を設定し、HPA と PodDisruptionBudget を検証済みであること
- マイグレーション手順がレビューされ、ロールバック手順が用意されていること
- ログが構造化され、集約先へ送られていること
- 主要なメトリクスとアラートが設定されていること
- トレースで主要フローの追跡が可能であること
- バックアップと復元手順が検証済みであること
推奨ツール一覧とバージョン固定方法
外部ツールはバージョン固定してインストール手順をリポジトリに残します。Makefile や tools/install.sh にまとめると便利です。
- 例: バージョン固定インストール(Makefile の一部)
|
1 2 3 4 5 6 |
install-tools: go install github.com/golang-migrate/migrate/v4/cmd/migrate@v4.15.2 go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.9.10 curl -sSfL -o /usr/local/bin/buf https://github.com/bufbuild/buf/releases/download/v1.19.0/buf-$(uname | tr '[:upper:]' '[:lower:]')-x86_64 && chmod +x /usr/local/bin/buf curl -sSfL -o /usr/local/bin/cosign https://github.com/sigstore/cosign/releases/download/v1.13.0/cosign-linux-amd64 && chmod +x /usr/local/bin/cosign |
- 補足:
- trivy や cosign などはリリースバイナリを固定した URL でダウンロードすると再現性が高まります。
- リポジトリに tools/versions.md を置き、CI も参照するようにします。
cosign の署名と運用注意
cosign の基本的な使い方と鍵運用、KMS・Keyless の選択肢、鍵ローテーションの注意点を示します。
- 鍵ペア方式(簡易例):
|
1 2 3 4 |
cosign generate-key-pair cosign sign --key cosign.key ghcr.io/yourorg/service:tag cosign verify --key cosign.pub ghcr.io/yourorg/service:tag |
- KMS(GCP)を使う例:
|
1 2 |
cosign sign --key gcpkms://projects/<proj>/locations/<loc>/keyRings/<kr>/cryptoKeys/<key> ghcr.io/yourorg/service:tag |
- Keyless(OIDC)署名は便利ですが、運用ポリシーと監査要件を検討してください。
- 鍵ローテーション: 公開鍵は検証側に配布しておき、ローテーション手順をドキュメント化します。検証ポリシーに複数キーの許容を組み込みます。
まとめ
設計から運用までを通じて、再現性と安全性を重視することが重要です。CI での生成差分チェック、ツールのバージョン固定、Compose CLI v2 の利用、Distroless の運用上の注意、pprof の安全な扱い、そしてシークレットを本番とローカルで分離して管理することを優先してください。これらを踏まえれば、Go マイクロサービス 開発 手順を現場で再現可能かつ安全に運用できます。