
Kong Gatewayを使ったマイクロサービスAPI基盤の一例
ゲームソリューション部の えがわ です。
本ブログはClassmethod SaaSで加速するゲーム開発 Advent Calendar 2025の23日目のブログとなります。
今回は、Kong Gatewayを使用したソーシャルゲーム向けマイクロサービスAPI基盤を試してみました。
本記事はAPI基盤の一例として、マイクロサービスアーキテクチャにおけるAPI Gateway導入のサンプルです。
実際のプロジェクトでは、要件に応じて構成やツールを選定してください。
ソースコードは以下のリポジトリに公開しています。
Kong Gatewayとは
Kong Gatewayは、APIリクエストを一元管理するAPI Gatewayです。
認証、レートリミット、ルーティングなどの機能をバックエンドサービスから切り離し、非機能要件をAPI Gateway層で処理できます。
マイクロサービスアーキテクチャでは、複数のサービスへのアクセスを一元化することで、クライアント側の実装をシンプルに保てます。
技術スタック
| カテゴリ | 技術 |
|---|---|
| バックエンド | Go 1.25 / Echo v4 |
| データベース | MySQL 8.4 (ローカル) / TiDB Cloud (本番) |
| コンテナ | Docker / ECS Fargate |
| API Gateway | Kong Gateway 3.12 |
| Control Plane | Kong Konnect (SaaS) |
| サービスディスカバリ | AWS Cloud Map |
| IaC | Terraform |
| API設定管理 | decK (GitOps) |
アーキテクチャ
全体構成
ハイブリッド型API Gatewayの構成
Kong Konnect(SaaS)をControl Plane、ECS FargateにデプロイしたKong GatewayをData Planeとして組み合わせています。
Control Plane(Kong Konnect SaaS)
- 設定の保存・管理
- 管理画面での設定確認・編集
- 分析・モニタリング
- WebSocket(443)でData Planeと常時接続
Data Plane(ECS Fargate上のKong Gateway)
- 実際のトラフィック処理
- ルーティング実行
- プラグイン実行(JWT認証、レートリミットなど)
- 証明書はAWS SSM Parameter Storeから取得
サービス構成
| サービス | ポート | 役割 | 主要機能 |
|---|---|---|---|
| User Service | 8080 | 認証・ユーザー管理 | ゲスト認証、JWT発行、通貨管理 |
| Gacha Service | 8080 | ガチャ抽選 | ガチャプール管理、抽選ロジック、Sagaオーケストレーション |
| Inventory Service | 8080 | アイテム管理 | アイテム付与、所持アイテム管理 |
| Kong Gateway | 8000 | API Gateway | JWT認証、レートリミット、ルーティング |
本プロジェクトではAPI Gatewayでの統一的なバリデーションと可読性を優先したため、HTTP/JSONを採用しました。一般的には、高スループット・低レイテンシが求められるユースケースではgRPCが検討対象になることもあります。
データベース構成(TiDB Cloud)
本プロジェクトでは、3つのマイクロサービスが単一のTiDB Cloudクラスターを共有しています。
一般的なマイクロサービスの原則では『サービスごとにDBを分離』が推奨されることが多いですが、本構成ではあえて共有DBを採用しています。
サービスごとにスキーマ(データベース)を分離しています。
| サービス | スキーマ名 | 主なテーブル |
|---|---|---|
| User Service | game_user | users, devices, currencies, refresh_tokens |
| Gacha Service | game_gacha | gacha_pools, gacha_items, gacha_histories, sagas |
| Inventory Service | game_inventory | user_items, item_masters |
この構成により、スキーマレベルでの分離を維持しつつ、運用コストを抑えられます。
将来的にサービスが成長した場合は、TiDBのスケーラビリティでDBがボトルネックになることなく対応できます。
認証システム
ゲスト認証
デバイスIDベースの認証を実装しています。初回アクセス時に自動でユーザーを作成し、JWTトークンを発行します。
curl -X POST http://localhost:8000/v1/auth/guest \
-H "Content-Type: application/json" \
-d '{
"device_id": "test-device-001",
"device_type": "ios",
"device_name": "iPhone 15"
}'
レスポンス:
{
"success": true,
"data": {
"user_id": "uuid",
"player_id": "PLY123456",
"access_token": "eyJhbG...",
"refresh_token": "dGhpcyBpcy...",
"is_guest": true
}
}
JWT認証
Kong GatewayでJWT検証を行い、無効なトークンには401 Unauthorizedを返却します。認証不要なエンドポイント(/v1/auth/guest)はJWT検証をスキップするよう設定しています。
routes:
# Guest authentication (NO JWT required)
- name: auth-guest-route
paths:
- ~/v1/auth/guest$
methods:
- POST
strip_path: false
preserve_host: false
# User routes (JWT required)
- name: users-route
paths:
- /v1/users
methods:
- GET
- PUT
strip_path: false
preserve_host: false
plugins:
- name: jwt
config:
claims_to_verify:
- exp
key_claim_name: iss
header_names:
- Authorization
ガチャシステム(Sagaパターン)
ガチャ抽選は複数のサービスにまたがる分散トランザクションのため、Sagaパターンで実装しています。
Sagaフロー
Saga状態の定義
type SagaStatus string
const (
StatusStarted SagaStatus = "STARTED"
StatusCurrencyReserved SagaStatus = "CURRENCY_RESERVED"
StatusDrawCompleted SagaStatus = "DRAW_COMPLETED"
StatusItemGranted SagaStatus = "ITEM_GRANTED"
StatusCompleted SagaStatus = "COMPLETED"
StatusCompensating SagaStatus = "COMPENSATING"
StatusCurrencyRefunded SagaStatus = "CURRENCY_REFUNDED"
StatusFailed SagaStatus = "FAILED"
)
Gacha ServiceがオーケストレーターとしてUser ServiceとInventory Serviceを呼び出し、各ステップでSagaの状態をDBに保存します。失敗時は補償トランザクションでロールバックを行います。
ガチャ実行の例
curl -X POST http://localhost:8000/v1/gacha/draw \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {access_token}" \
-d '{
"pool_id": "pool-standard",
"draw_count": 10
}'
レスポンス:
{
"success": true,
"data": {
"saga_id": "uuid",
"status": "COMPLETED",
"results": [
{
"item_master_id": "char-ssr-001",
"rarity": "SSR",
"is_new": true,
"is_pickup": false
}
],
"cost": {
"currency_type": "free_gem",
"amount": 3000
},
"pity": {
"count": 10,
"max_count": 90
}
}
}
API Gateway機能
レートリミット
サービス別にレートリミットを設定しています。
services:
- name: user-service
plugins:
- name: rate-limiting
config:
minute: 30
policy: local
fault_tolerant: true
- name: gacha-service
plugins:
- name: rate-limiting
config:
minute: 10
policy: local
fault_tolerant: true
- name: inventory-service
plugins:
- name: rate-limiting
config:
minute: 60
policy: local
fault_tolerant: true
超過時は429 Too Many Requestsを返却します。
OAS Validation(Enterprise機能)
OpenAPI仕様に基づくリクエスト検証を行います。
リクエストボディ、ヘッダー、クエリパラメータ、パスパラメータを検証し、不正なリクエストには400 Bad Requestを返却します。
plugins:
- name: oas-validation
config:
api_spec: "${OAS_API_SPEC}"
api_spec_encoded: false
validate_request_body: true
validate_request_header_params: true
validate_request_query_params: true
validate_request_uri_params: true
validate_response_body: false
verbose_response: true
Correlation ID
リクエストごとにUUIDを生成し、X-Request-IDヘッダーでバックエンドに伝播します。ログトレーシングに活用できます。
plugins:
- name: correlation-id
config:
header_name: X-Request-ID
generator: uuid
echo_downstream: true
インフラ構成(Terraform)
ディレクトリ構成
terraform/
├── main.tf # モジュール呼び出し
├── variables.tf # 変数定義
├── outputs.tf # 出力定義
├── versions.tf # バージョン指定
└── modules/
├── vpc/ # VPC・サブネット
├── security_groups/ # セキュリティグループ
├── alb/ # ALB・ターゲットグループ
├── cloudmap/ # Cloud Map(サービスディスカバリ)
├── ecr/ # ECRリポジトリ
├── ecs/ # ECSクラスター・タスク定義・サービス
├── ssm/ # SSM Parameter Store
└── github_oidc/ # GitHub Actions用OIDC
モジュール構成
module "vpc" {
source = "./modules/vpc"
project_name = var.project_name
vpc_cidr = var.vpc_cidr
}
module "cloudmap" {
source = "./modules/cloudmap"
project_name = var.project_name
vpc_id = module.vpc.vpc_id
namespace_name = "game.local"
}
module "ecs" {
source = "./modules/ecs"
project_name = var.project_name
private_subnet_ids = module.vpc.private_subnet_ids
kong_security_group_id = module.security_groups.kong_security_group_id
kong_konnect_control_plane_endpoint = var.kong_konnect_control_plane_endpoint
# ...
}
Kong Data Planeタスク定義
resource "aws_ecs_task_definition" "kong" {
family = "${var.project_name}-kong"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
execution_role_arn = aws_iam_role.ecs_task_execution.arn
task_role_arn = aws_iam_role.ecs_task.arn
container_definitions = jsonencode([
{
name = "kong"
image = "kong/kong-gateway:3.12"
essential = true
environment = [
{ name = "KONG_ROLE", value = "data_plane" },
{ name = "KONG_DATABASE", value = "off" },
{ name = "KONG_CLUSTER_MTLS", value = "pki" },
{ name = "KONG_CLUSTER_CONTROL_PLANE", value = var.kong_konnect_control_plane_endpoint }
# ...
]
secrets = [
{ name = "KONG_CLUSTER_CERT_DATA", valueFrom = var.kong_cluster_cert_arn },
{ name = "KONG_CLUSTER_CERT_KEY_DATA", valueFrom = var.kong_cluster_cert_key_arn }
]
}
])
}
AWS Cloud Map(サービスディスカバリ)
Kong GatewayからバックエンドサービスへのルーティングにCloud Mapを使用しています。
| サービス | DNS名 |
|---|---|
| User Service | user.game.local:8080 |
| Gacha Service | gacha.game.local:8080 |
| Inventory Service | inventory.game.local:8080 |
ECSサービスをCloud Mapに登録することで、タスクのIPアドレスが自動的にDNSに登録されます。
resource "aws_ecs_service" "user" {
name = "${var.project_name}-user"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.user.arn
# ...
service_registries {
registry_arn = var.user_service_registry_arn
container_name = "user"
}
}
GitOps(decK)
Kong設定の管理
Kong GatewayのルーティングやプラグインをYAMLファイルで定義し、decKを使用してKong Konnectに同期します。
kong/
└── kong.yaml # Kong設定ファイル
CI/CDパイプライン
GitHub Actionsで自動デプロイを行います。
Pull Request時
deck gateway diffで変更内容を表示- PRコメントに差分を投稿
Mainブランチマージ時
- OpenAPI仕様をKong設定に注入
deck gateway syncでKong Konnectに同期
jobs:
sync:
name: Kong Config Sync
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Inject OpenAPI spec into Kong config
run: |
yq -o=json '.' openapi.yaml | jq -c '.' > /tmp/oas-spec.json
cp kong/kong.yaml kong/kong-with-oas.yaml
export OAS_SPEC=$(cat /tmp/oas-spec.json)
yq -i '
(.plugins[] | select(.name == "oas-validation") | .config.api_spec) = strenv(OAS_SPEC)
' kong/kong-with-oas.yaml
- name: Sync to Kong Konnect
run: |
deck gateway sync kong/kong-with-oas.yaml \
--konnect-addr $KONG_ADDR \
--konnect-token $KONG_TOKEN \
--konnect-control-plane-name $KONG_CP_NAME
設定変更はGitHubにマージするだけで、本番環境に反映されます。
初回セットアップ
CI/CDパイプラインが動作するためには、まずインフラを手動で構築する必要があります。
事前準備
- Kong Konnectアカウント: Kong KonnectでControl Planeを作成し、Data Plane用の証明書を取得
- TiDB Cloudアカウント: データベースクラスターを作成し、接続情報を取得
- AWSアカウント: Terraformを実行するためのIAM権限を設定
Kongの証明書取得は以下の記事をご確認ください。
手動でのTerraform実行
初回は以下の手順でインフラを構築します。
cd terraform
# 変数ファイルを作成
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvarsを編集し、各種シークレットを設定
# 初期化
terraform init
# 実行計画を確認
terraform plan
# インフラを構築
terraform apply
Dockerイメージのビルド・プッシュ
ECRリポジトリが作成されたら、初回のDockerイメージをプッシュします。
# ECRにログイン
aws ecr get-login-password --region ap-northeast-1 | \
docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com
# 各サービスをビルド・プッシュ
cd backend
# User Service
docker build -t <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/user-service:latest \
-f docker/user-service/Dockerfile .
docker push <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/user-service:latest
# Gacha Service
docker build -t <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/gacha-service:latest \
-f docker/gacha-service/Dockerfile .
docker push <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/gacha-service:latest
# Inventory Service
docker build -t <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/inventory-service:latest \
-f docker/inventory-service/Dockerfile .
docker push <ACCOUNT_ID>.dkr.ecr.ap-northeast-1.amazonaws.com/kong-game/inventory-service:latest
GitHub Secretsの設定
CI/CDパイプラインが動作するよう、以下のSecretsをGitHubリポジトリに設定します。
| Secret名 | 説明 |
|---|---|
AWS_ROLE_ARN |
GitHub OIDC用のIAMロールARN |
KONG_KONNECT_ADDR |
Kong KonnectのAPIエンドポイント |
KONG_KONNECT_TOKEN |
Kong Konnectのアクセストークン |
KONG_KONNECT_CP_NAME |
Control Plane名 |
KONG_CLUSTER_CERT |
Data Plane用証明書 |
KONG_CLUSTER_CERT_KEY |
Data Plane用秘密鍵 |
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD |
TiDB Cloud接続情報 |
JWT_SECRET |
JWT署名用シークレット |
初回セットアップが完了すれば、以降はGitHubへのPush/Mergeで自動デプロイが実行されます。
デプロイフロー(CI/CD)
本プロジェクトでは、GitHub Actionsを使用した3種類のCI/CDパイプラインを用意しています。
Terraformデプロイ(インフラ)
terraform/配下のファイルが変更された際に実行されます。
| トリガー | 実行内容 |
|---|---|
| Pull Request | terraform plan → 変更内容をレビュー |
| Main マージ | terraform apply → AWSリソースを更新 |
バックエンドデプロイ
backend/配下のファイルが変更された際に実行されます。変更されたサービスのみビルド・デプロイする効率的なパイプラインです。
| 変更対象 | ビルド対象 |
|---|---|
backend/internal/user/** |
User Service のみ |
backend/internal/gacha/** |
Gacha Service のみ |
backend/internal/inventory/** |
Inventory Service のみ |
backend/internal/shared/**, go.mod |
全サービス |
decKデプロイ(Kong設定)
kong/配下またはopenapi.yamlが変更された際に実行されます。
| トリガー | 実行内容 |
|---|---|
| Pull Request | deck gateway diff → 変更差分をPRにコメント |
| Main マージ | deck gateway sync → Kong Konnectに即時反映 |
OpenAPI仕様(openapi.yaml)はCI/CD時にKong設定に注入されるため、API仕様とOAS Validationプラグインの設定が常に同期されます。
ローカル開発環境
Docker Composeで全サービスを起動できます。
cd backend
docker-compose up -d
起動後、以下のエンドポイントでアクセスできます。
- Kong Gateway: http://localhost:8000
- User Service: http://localhost:8081
- Gacha Service: http://localhost:8082
- Inventory Service: http://localhost:8083
ローカル環境と本番環境の違い
ローカル開発環境ではKong Gateway OSS版を使用しているため、エンタープライズ専用機能は利用できません。
| 機能 | ローカル(OSS) | 本番(Konnect) |
|---|---|---|
| JWT認証 | ✅ 利用可 | ✅ 利用可 |
| レートリミット | ✅ 利用可 | ✅ 利用可 |
| Correlation ID | ✅ 利用可 | ✅ 利用可 |
| OAS Validation | ❌ スキップ | ✅ 利用可 |
ローカル用のKong設定(backend/kong-local.yaml)では、OAS Validationプラグインを除外しています。
本番環境でのみOpenAPI仕様に基づくリクエスト検証が有効になります。
さいごに
今回はKong Gatewayを使用したマイクロサービスAPI基盤を構築してみました。
Kong Konnect(SaaS)とECS Fargateを組み合わせることで、運用負荷を軽減しつつ柔軟なAPI管理が実現できます。
GitOpsによる設定管理やSagaパターンによる分散トランザクションなど、実践的なパターンも試してみています。
この記事がどなたかの参考になれば幸いです。










