多租户 LLM API 管理平台 — 架构设计文档 v1.0
AIGateway 是一个面向代理商和企业的多租户 LLM API 管理平台。代理商绑定自己的域名,设置模型售价,平台统一管理上游渠道、认证、计费。终端用户通过代理商域名接入,使用兼容 OpenAI 格式的 API 调用各种大模型。
每个代理商一个租户,域名路由自动识别,数据 tenant_id 强制隔离。
代理商只需绑域名 + 设价格,用户体系和 SSO 由平台统一提供。
基于 Higress AI Proxy 插件,原生支持 OpenAI、Claude、Gemini 等 40+ 模型提供商。
服务独立部署、独立扩缩,网关层和业务层互不影响。
角色分两个维度:在哪(租户层级) × 干什么(职能角色)。角色定义全局统一,权限范围限定在各自租户内。平台的销售能看所有代理商数据,代理商的销售只能看自己租户下的客户。
平台主站 (TenantPlatform) 代理商租户 (TenantReseller) ├── owner 管理员(全部权限) ├── owner 管理员(租户内全部权限) ├── operator 运营(租户设置/成员管理) ├── sales 销售(客户管理/名下用量) ├── sales 销售(客户管理/名下用量) ├── finance 财务(定价/账单/结算) ├── finance 财务(定价/账单/结算) └── user 终端用户(API调用/看自己用量) ├── tech 技术(渠道管理/系统监控) └── user 终端用户(API调用/看自己用量)
| 角色 | 定位 | 平台可用 | 代理商可用 | 核心权限 |
|---|---|---|---|---|
| owner | 管理员 | ✅ | ✅ | 全部权限,角色分配,成员管理 |
| operator | 运营 | ✅ | ❌ | 租户设置,成员管理,客户管理 |
| sales | 销售 | ✅ | ✅ | 客户邀请/管理,查看名下客户用量,API Key 管理 |
| finance | 财务 | ✅ | ✅ | 模型定价,账单查看,结算/提现,客户列表(只读) |
| tech | 技术 | ✅ | ❌ | 渠道管理,系统监控/日志,API Key 管理 |
| user | 终端用户 | ✅ | ✅ | 使用 API,查看自己的用量和额度 |
| 功能模块 | owner | operator | sales | finance | tech | user |
|---|---|---|---|---|---|---|
| 租户设置(域名/Logo) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| 成员管理(邀请/禁用) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| 角色分配 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| 客户邀请/管理 | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| 查看客户列表 | ✅ | ✅ | ✅ (名下) | ✅ (只读) | ❌ | ❌ |
| 模型定价 | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
| 查看用量/账单 | ✅ | ✅ | ✅ (名下客户) | ✅ (全部) | ❌ | ✅ (仅自己) |
| 结算/提现 | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
| 渠道管理 | ✅* | ❌ | ❌ | ❌ | ✅* | ❌ |
| API Key 管理 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ (仅自己) |
| 系统监控/日志 | ✅* | ❌ | ❌ | ❌ | ✅* | ❌ |
销售有一个其他角色没有的概念:客户归属。通过 customer_bindings 表记录客户属于哪个销售,查询用量和账单时自动过滤为名下客户数据。
平台销售 Alice 代理商A 销售 Bob ├── 客户: 代理商A (全代理商) ├── 客户: 张三 (终端用户) ├── 客户: 代理商B ├── 客户: 李四 └── 客户: 代理商C └── 客户: 王五 Alice 看到的用量 = 代理商A+B+C Bob 看到的用量 = 张三+李四+王五 的总消费数据 在代理商A 下的消费数据
支持一个用户拥有多个角色。例如小公司的老板可能同时是 owner + finance,通过 user_roles 表实现多对多关系。JWT 中携带角色列表,权限取并集。
用户请求 (api.代理商.com)
│
▼
┌──────────────────────────────────────────────────────────┐
│ Higress 网关层 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ │
│ │ 域名路由 │ │ 自动 TLS │ │ 限流 │ │ AI Proxy │ │
│ └──────────┘ └──────────┘ └────────┘ └──────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Wasm 插件: 用量上报 / Trace 注入 │ │
│ └──────────────────────────────────────────────────┘ │
└────────────┬──────────────┬──────────────┬───────────────┘
│ │ │
/oauth/* /api/* /v1/chat/completions
│ │ │
┌──────▼──────┐ ┌────▼─────┐ │ (Higress 直接代理)
│ Auth Svc │ │ Core Svc │ │
│ │ │ │ ▼
│ SSO 登录 │ │ 租户管理 │ 上游模型 API
│ JWT 签发 │ │ 代理商 │ (OpenAI/Claude/
│ RBAC │ │ API Key │ Gemini/...)
└──────┬──────┘ └────┬─────┘
│ │
│ ┌────▼──────┐ Kafka ┌───────────┐
│ │ Config │ ─────────▶ │ Billing │
│ │ Syncer │ │ Svc │
│ └───────────┘ │ │
│ │ │ 计量/额度 │
│ Higress API/CRD │ 定价/结算 │
│ └─────┬─────┘
│ │
─────────────┴───────────────────────────────────────┴──────
基础设施层
MySQL (主从) · Redis (Sentinel) · Kafka (3 Broker)
ClickHouse · Prometheus
────────────────────────────────────────────────────────────
平台级 SSO 中心,所有租户共享同一套认证体系,代理商无需配置任何 OAuth。
type Role string
const (
RoleOwner Role = "owner"
RoleOperator Role = "operator"
RoleSales Role = "sales"
RoleFinance Role = "finance"
RoleTech Role = "tech"
RoleUser Role = "user"
)
type TenantType string
const (
TenantPlatform TenantType = "platform" // 平台主站
TenantReseller TenantType = "reseller" // 代理商
)
// 各租户类型可分配的角色
var AvailableRoles = map[TenantType][]Role{
TenantPlatform: {RoleOwner, RoleOperator, RoleSales, RoleFinance, RoleTech, RoleUser},
TenantReseller: {RoleOwner, RoleSales, RoleFinance, RoleUser},
}
func RequireRoles(roles ...Role) gin.HandlerFunc {
return func(c *gin.Context) {
userRoles := auth.RolesFromContext(c)
for _, required := range roles {
if userRoles.Has(required) {
c.Next()
return
}
}
c.AbortWithStatus(403)
}
}
// 使用示例
r.GET("/api/customers", RequireRoles(RoleOwner, RoleSales, RoleOperator))
r.POST("/api/pricing", RequireRoles(RoleOwner, RoleFinance))
r.POST("/api/settle", RequireRoles(RoleOwner, RoleFinance))
r.GET("/api/channels", RequireRoles(RoleOwner, RoleTech)) // 仅平台租户有效
func (s *UsageService) ListBySales(ctx context.Context, salesID int64) ([]Usage, error) {
// 1. 查出该销售名下的客户 ID 列表
customerIDs := s.bindingRepo.GetCustomerIDs(ctx, salesID)
// 2. 只查这些客户的用量(数据隔离)
return s.usageRepo.ListByCustomers(ctx, customerIDs)
}
所有管理面的 CRUD 操作,操作完成后发事件到 Kafka。
纯异步服务,不在请求关键路径上,消费用量事件做计费。
Core 和 Higress 之间的桥梁,将业务配置变更同步为 Higress 的路由/Consumer 配置。
运行在 Higress 内部的 Wasm 插件,每次 AI 请求完成后提取用量数据并上报。
| 调用方 | 被调方 | 方式 | 场景 |
|---|---|---|---|
| Higress | Auth | gRPC | API Key 鉴权 |
| Core | Auth | gRPC | 用户管理操作时校验权限 |
| Core | Kafka | 事件 | 租户/Key 变更通知 |
| Syncer | Kafka | 消费 | 消费变更事件,同步 Higress |
| Wasm | Kafka | 事件 | 用量数据上报 |
| Billing | Kafka | 消费 | 消费用量事件,扣费 |
| Syncer | Higress | API/CRD | 下发路由和 Consumer 配置 |
共享数据库 + tenant_id 隔离。所有数据访问通过 TenantScope 自动注入 tenant_id,防止数据越权。
// TenantScope 所有查询自动带 tenant_id
func DB(ctx context.Context) *gorm.DB {
tenantID := tenant.FromContext(ctx)
if tenantID == "" {
panic("missing tenant_id in context") // 开发阶段直接 panic 暴露问题
}
return db.Where("tenant_id = ?", tenantID)
}
// AdminDB 平台管理员跨租户操作(仅 platform_admin 可用)
func AdminDB(ctx context.Context) *gorm.DB {
if !rbac.IsPlatformAdmin(ctx) {
panic("AdminDB requires platform_admin role")
}
return db
}
CREATE TABLE tenants (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
slug VARCHAR(64) UNIQUE NOT NULL, -- 唯一标识 (url-safe)
name VARCHAR(128) NOT NULL, -- 显示名称
type VARCHAR(16) DEFAULT 'reseller', -- platform=平台主站 / reseller=代理商
domain VARCHAR(255) UNIQUE, -- 自定义域名
parent_id BIGINT DEFAULT NULL, -- 上级代理商 (NULL=平台直管)
logo_url VARCHAR(512), -- 登录页 Logo
theme_color VARCHAR(7) DEFAULT '#6c8cff', -- 主题色
config JSON, -- 功能开关等配置
status TINYINT DEFAULT 1, -- 1=active 0=disabled
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_parent (parent_id),
INDEX idx_domain (domain)
);
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
email VARCHAR(255),
phone VARCHAR(20),
password VARCHAR(255), -- bcrypt hash
status TINYINT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_tenant_user (tenant_id, username),
INDEX idx_tenant (tenant_id)
);
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
tenant_id BIGINT NOT NULL,
role VARCHAR(32) NOT NULL, -- owner/operator/sales/finance/tech/user
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, tenant_id, role),
INDEX idx_tenant (tenant_id)
);
CREATE TABLE customer_bindings (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
customer_id BIGINT NOT NULL, -- 终端用户 ID
sales_id BIGINT NOT NULL, -- 所属销售
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_customer (tenant_id, customer_id),
INDEX idx_sales (tenant_id, sales_id)
);
-- 销售查用量时,只能看到自己名下客户的数据
CREATE TABLE channels (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(128) NOT NULL, -- "OpenAI 主力", "Claude 备用"
provider VARCHAR(32) NOT NULL, -- openai / claude / gemini / ...
api_key_enc VARBINARY(1024) NOT NULL, -- AES 加密存储
base_url VARCHAR(512), -- 自定义 endpoint
models JSON NOT NULL, -- ["gpt-4o","gpt-4o-mini",...]
priority INT DEFAULT 0, -- 越大越优先
weight INT DEFAULT 100, -- 负载均衡权重
status TINYINT DEFAULT 1,
max_retry INT DEFAULT 2,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-- 注意:无 tenant_id,渠道是平台级资源
);
CREATE TABLE tokens (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
name VARCHAR(64), -- "生产环境 Key"
key_hash VARCHAR(64) NOT NULL UNIQUE, -- SHA256(sk-xxx),只存 hash
key_prefix VARCHAR(12) NOT NULL, -- "sk-abc1" 用于展示
models JSON, -- 允许的模型列表,NULL=全部
quota BIGINT DEFAULT -1, -- 总额度(token数),-1=不限
used_quota BIGINT DEFAULT 0,
rate_limit INT DEFAULT 60, -- RPM
expires_at DATETIME,
status TINYINT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_tenant (tenant_id),
INDEX idx_hash (key_hash)
);
CREATE TABLE pricing (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
tenant_id BIGINT DEFAULT 0, -- 0=平台默认价,其他=租户自定义
model VARCHAR(64) NOT NULL, -- "gpt-4o"
input_price DECIMAL(12,6) NOT NULL, -- 每百万 input token 价格
output_price DECIMAL(12,6) NOT NULL, -- 每百万 output token 价格
currency VARCHAR(3) DEFAULT 'CNY',
UNIQUE KEY uk_tenant_model (tenant_id, model)
);
CREATE TABLE usage_logs (
id UUID DEFAULT generateUUIDv4(),
trace_id String,
tenant_id UInt64,
user_id UInt64,
token_id UInt64,
channel_id UInt64,
model String,
prompt_tokens UInt32,
completion_tokens UInt32,
total_tokens UInt32,
cost Decimal(12,6), -- 向用户收费
upstream_cost Decimal(12,6), -- 上游成本
latency_ms UInt32,
status String, -- success / error
error_msg String DEFAULT '',
created_at DateTime DEFAULT now()
) ENGINE = MergeTree()
ORDER BY (tenant_id, created_at)
PARTITION BY toYYYYMM(created_at)
TTL created_at + INTERVAL 6 MONTH;
全部自建在云机器上,通过 K8s StatefulSet 管理有状态服务。
部署:1 主 + 1 从,StatefulSet,PVC 持久化存储
职责:租户、用户、渠道、令牌、定价等核心业务数据
推荐 Operator:mysql-operator (Oracle 官方) 或 Percona Operator
备份:CronJob 定时 mysqldump 到对象存储
部署:3 节点 Sentinel 模式(1主2从+3哨兵)
职责:①额度实时扣减 ②租户↔域名映射缓存 ③分布式限流计数器 ④JWT 黑名单
推荐 Operator:Redis Operator by Spotahome
部署:3 Broker,KRaft 模式(无 ZooKeeper),Strimzi Operator 管理
Topics:tenant.events / usage.events / alert.events
为什么选 Kafka:用量数据吞吐大、需要持久化回放、consumer group 天然支持多实例消费
部署:单节点起步(日均千万级请求够用),后续可扩 shard
职责:用量日志存储、多维度聚合报表(按租户/模型/时间段)
数据保留:TTL 6 个月自动清理
| 组件 | 版本 | 部署方式 | 节点数 | 持久化 |
|---|---|---|---|---|
| MySQL | 8.0 | StatefulSet + Operator | 2 (1主1从) | PVC 100Gi+ |
| Redis | 7.x | StatefulSet + Sentinel | 3 (1主2从+3哨兵) | PVC 10Gi |
| Kafka | 3.7+ | Strimzi Operator | 3 Broker | PVC 50Gi/broker |
| ClickHouse | 24.x | StatefulSet | 1 (起步) | PVC 200Gi+ |
| Higress | latest | Helm Chart | 2+ (HPA) | 无状态 |
| cert-manager | 1.14+ | Helm Chart | 1 | 无 |
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐
│ Higress │ │ Auth │ │ Core │ │Billing │ │ Syncer │
│ (Envoy) │ │ Svc │ │ Svc │ │ Svc │ │ │
└────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬─────┘
│ │ │ │ │
│ OpenTelemetry SDK (traces + metrics + logs) │
│ │ │ │ │
└────────────┴────────────┴────────────┴────────────┘
│
┌────────────▼────────────┐
│ OTel Collector │
│ (DaemonSet, 每节点1个) │
└───┬────────┬────────┬───┘
│ │ │
┌────▼──┐ ┌──▼────┐ ┌─▼─────┐
│Jaeger │ │Prome- │ │ Loki │
│ │ │theus │ │ │
│Traces │ │Metrics│ │ Logs │
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
└─────────┼─────────┘
▼
┌──────────┐
│ Grafana │
│ 统一看板 │
└──────────┘
{
"ts": "2026-03-18T10:00:00.123Z",
"level": "info",
"svc": "billing",
"trace_id": "a1b2c3d4e5f6",
"tenant_id": "t_001",
"user_id": "u_456",
"action": "quota.deduct",
"model": "gpt-4o",
"tokens": 230,
"cost": 0.0046,
"remaining_quota": 987654,
"msg": "quota deducted successfully"
}
| 看板 | 核心指标 | 告警规则 |
|---|---|---|
| API 总览 | 总 QPS、P99 延迟、错误率、token 吞吐 | 错误率 > 5% 持续 3 分钟 |
| 租户维度 | 各租户 QPS、token 消耗、额度剩余 | 额度 < 10% 预警 |
| 上游渠道 | 各渠道成功率、延迟、故障转移次数 | 渠道成功率 < 95% |
| 基础设施 | CPU/MEM、Pod 状态、Kafka lag | consumer lag > 10000 |
| 营收 | 日收入、成本、利润、代理商分成 | - |
auth-svc.aigateway.svc.cluster.local:50051core-svc.aigateway.svc.cluster.local:50052# 外部流量通过 LoadBalancer Service 进入 Higress # Higress 按 Host + Path 分发到后端服务 # AI API 请求 —— Higress 自己处理(ai-proxy 插件) # api.代理商.com/v1/chat/completions → Higress ai-proxy → 上游模型 # 管理 API —— 转发到 Core # api.代理商.com/api/* → core-svc.aigateway.svc.cluster.local:8081 # 认证 —— 转发到 Auth # auth.平台.com/* → auth-svc.aigateway.svc.cluster.local:8080
Node 1 (8C16G) - Master + Worker ├── K8s Control Plane (API Server, etcd, Scheduler) ├── Higress Gateway × 1 ├── auth-svc × 1 ├── core-svc × 1 └── OTel Collector Node 2 (8C16G) - Worker ├── Higress Gateway × 1 ├── billing-svc × 1 ├── config-syncer × 1 ├── MySQL Primary ├── Redis (master + sentinel) └── OTel Collector Node 3 (8C16G) - Worker ├── Kafka Broker × 1 (起步阶段 1 broker 够了) ├── ClickHouse ├── MySQL Replica ├── Redis (replica × 2 + sentinel × 2) ├── Prometheus + Grafana + Jaeger + Loki └── OTel Collector
Node 1-3 (4C8G) - Master × 3 ├── K8s Control Plane (HA) ├── etcd cluster └── OTel Collector Node 4 (8C16G) - Worker: 业务服务 ├── Higress Gateway × 2 (HPA) ├── auth-svc × 2 ├── core-svc × 2 ├── billing-svc × 2 └── config-syncer × 1 Node 5 (8C32G) - Worker: 数据库 ├── MySQL Primary ├── Redis Master + Sentinel ├── Kafka Broker × 1 └── ClickHouse Node 6 (8C16G) - Worker: 数据库副本 + 监控 ├── MySQL Replica ├── Redis Replica + Sentinel ├── Kafka Broker × 2 ├── Prometheus + Grafana ├── Jaeger + Loki └── OTel Collector
┌──────────────────────┐
│ Master × 3 │ K8s 控制面高可用
│ (4C8G each) │
└──────────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ Gateway Pool │ │ App Pool │
│ Node × 2~N │ │ Node × 2~N │
│ (8C16G) │ │ (8C16G) │
│ │ │ │
│ Higress (HPA) │ │ auth-svc │
│ 专跑网关 │ │ core-svc │
│ taint: gateway │ │ billing-svc │
└──────────────────┘ │ config-syncer │
└──────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ DB Pool │ │ Monitor Pool │
│ Node × 2~3 │ │ Node × 1~2 │
│ (8C32G, SSD) │ │ (8C16G) │
│ │ │ │
│ MySQL 主从 │ │ Prometheus │
│ Redis Sentinel │ │ Grafana │
│ Kafka 3 Broker │ │ Jaeger │
│ ClickHouse │ │ Loki │
│ taint: database │ │ taint: monitor │
└──────────────────┘ └──────────────────┘
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: higress-gateway
namespace: higress-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: higress-gateway
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # CPU 60% 开始扩
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
# 需要配合 KEDA (Kubernetes Event-Driven Autoscaling)
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: billing-svc-scaler
namespace: aigateway
spec:
scaleTargetRef:
name: billing-svc
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: kafka
metadata:
bootstrapServers: kafka.middleware.svc.cluster.local:9092
consumerGroup: billing-consumer
topic: usage.events
lagThreshold: "1000" # lag > 1000 开始扩
# 1. 新机器上执行 (加入集群) kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> # 2. Master 上打标签 (指定节点池) kubectl label node new-node-1 node-pool=gateway # 网关池 # 或 kubectl label node new-node-1 node-pool=app # 业务池 # 或 kubectl label node new-node-1 node-pool=database # 数据库池 # 3. 如果是数据库池,加 taint 防止业务 Pod 调度上来 kubectl taint nodes new-node-1 dedicated=database:NoSchedule # 4. 完事。HPA 会自动利用新节点的资源扩展 Pod
Developer
│ git push
▼
GitHub / GitLab
│
▼
CI Pipeline (GitHub Actions / GitLab CI)
├── Stage 1: Lint
│ └── golangci-lint run ./...
├── Stage 2: Test
│ └── go test ./... -race -cover
├── Stage 3: Build (并行)
│ ├── docker build -f deploy/docker/Dockerfile.auth → registry/auth:v1.2.3
│ ├── docker build -f deploy/docker/Dockerfile.core → registry/core:v1.2.3
│ ├── docker build -f deploy/docker/Dockerfile.billing → registry/billing:v1.2.3
│ └── docker build -f deploy/docker/Dockerfile.syncer → registry/syncer:v1.2.3
└── Stage 4: Push
└── docker push → Harbor (自建镜像仓库)
│
▼
ArgoCD (监听 Git 仓库中的 K8s manifests)
│ 检测到镜像 tag 变化
▼
K8s Cluster
└── Rolling Update (零停机)
name: CI/CD
on:
push:
branches: [main]
tags: ['v*']
jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- run: golangci-lint run ./...
- run: go test ./... -race -coverprofile=coverage.out
build-push:
needs: lint-test
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
strategy:
matrix:
service: [auth, core, billing, syncer]
steps:
- uses: actions/checkout@v4
- uses: docker/build-push-action@v5
with:
file: deploy/docker/Dockerfile.${{ matrix.service }}
tags: harbor.内部域名/aigateway/${{ matrix.service }}:${{ github.ref_name }}
push: true
# Wasm 插件单独构建
build-wasm:
needs: lint-test
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.24' }
- run: |
cd plugin/usage-reporter
GOOS=wasip1 GOARCH=wasm go build -o main.wasm
- run: | # 打成 OCI 镜像推到 Harbor
docker build -t harbor.内部域名/aigateway/usage-reporter:${{ github.ref_name }} plugin/usage-reporter
docker push harbor.内部域名/aigateway/usage-reporter:${{ github.ref_name }}
aigateway/
├── api/
│ ├── proto/ # gRPC 接口定义
│ │ ├── auth/auth.proto
│ │ ├── core/core.proto
│ │ ├── billing/billing.proto
│ │ └── common/common.proto
│ └── openapi/gateway.yaml # REST API 定义
│
├── cmd/ # 服务入口 (每个服务一个 main.go)
│ ├── auth/main.go
│ ├── core/main.go
│ ├── billing/main.go
│ └── syncer/main.go
│
├── internal/
│ ├── auth/ # 认证服务
│ │ ├── server.go # gRPC server
│ │ ├── handler/ # HTTP handler
│ │ ├── service/ # 业务逻辑 (sso/jwt/rbac)
│ │ └── repo/ # 数据访问
│ │
│ ├── core/ # 核心业务
│ │ ├── server.go
│ │ ├── handler/
│ │ ├── service/ # tenant/reseller/channel/token/model
│ │ └── repo/
│ │
│ ├── billing/ # 计费服务
│ │ ├── server.go
│ │ ├── consumer/ # Kafka consumer
│ │ ├── service/ # metering/quota/pricing/settlement
│ │ └── repo/
│ │
│ ├── syncer/ # 配置同步
│ │ ├── syncer.go
│ │ ├── consumer/
│ │ ├── higress/ # Higress API client
│ │ └── reconciler.go
│ │
│ └── pkg/ # 内部共享包
│ ├── tenant/context.go
│ ├── database/ # mysql/redis/clickhouse/migrate
│ ├── mq/ # kafka producer/consumer
│ ├── otel/init.go # OpenTelemetry 初始化
│ ├── jwt/jwt.go
│ └── config/config.go
│
├── plugin/ # Higress Wasm 插件 (独立 go.mod)
│ └── usage-reporter/
│ ├── main.go
│ ├── go.mod
│ └── Dockerfile
│
├── web/ # 前端 (后期)
│ ├── admin/ # 平台管理后台
│ └── console/ # 代理商控制台
│
├── deploy/
│ ├── docker/ # Dockerfile × 4
│ ├── k8s/
│ │ ├── base/ # Kustomize base (deployment/svc/hpa per service)
│ │ └── overlays/ # dev / prod 环境差异
│ └── infra/ # 中间件 yaml (mysql/redis/kafka/clickhouse/o11y)
│
├── scripts/
│ ├── gen-proto.sh
│ └── migrate.sh
│
├── go.mod
├── Makefile
└── .github/workflows/
├── ci.yaml
└── cd.yaml