Agones SDK-Server 与 Allocator
前言
Agones 通过 SDK-Server 让 GameServer 自己管理生命周期状态。每个 GameServer 启动时会连接本地的 SDK Server,通过 gRPC API 同步状态。
在实际部署时,sdk-server 会作为一个 sidecar 容器,和 gameserver 容器共享 network namespace,所以 gmaeserver 可以直接以 localhost 访问 sdk-server 的 api。
sdk-server 作为 agones 和 gameserver 之间的状态同步器,负责将 gameserver 的状态同步给 agones,以及将 agones 的分配请求同步给 gameserver。
Allocator Service
Allocator 是 Agones 提供的 gRPC 服务,用于分配 GameServer。它监听集群中所有 Ready 状态的 GameServer,当收到分配请求时,选择一个合适的 GameServer 并将其状态改为 Allocated。
Allocator 提供了两种分配方式:
- gRPC Service - 直接调用 gRPC API(适合高性能、安全性要求高的场景,通过mtls认证)
- Allocation API - 通过 Kubernetes CRD
GameServerAllocation(更简单,通过k8s api调用)
核心 API
- Ready() - 标记就绪,可以被分配
- Health() - 发送心跳,保持健康状态
- Shutdown() - 通知关闭
- SetAnnotation() - 设置自定义信息(如 自定义的对外访问地址)
- WatchGameServer() - 监听状态变化
状态流转
Port -> Ready -> Allocated -> Shutdown
- Port - 刚启动,等待 Ready
- Ready - 调用
Ready()后进入,等待分配 - Allocated - 被 match-maker 分配后进入,开始游戏逻辑
- Shutdown - 调用
Shutdown()或收到关闭信号后进入
一个dedicate-server和 match-maker通过 sdk-server 和 allocator 交互的例子
dedicate-server
启动流程:
sdk, _ := agones.NewSDK()
sdk.SetAnnotation("public_address", "127.0.0.1:7001") // 设置自定义地址
sdk.Ready() // 标记就绪
// 每 2 秒发送心跳
ticker := time.NewTicker(2 * time.Second)
for range ticker.C {
sdk.Health()
}
// 监听状态变化
sdk.WatchGameServer(func(gs *sdk.GameServer) {
switch gs.Status.State {
case "Allocated":
// 执行业务逻辑
case "Shutdown":
// 清理资源
}
})
match-maker
通过 GameServerAllocation API 分配 GameServer。这是 Kubernetes CRD 资源,创建后会由 Agones 的 Allocator 处理:
// 创建 GameServerAllocation 对象
allocation := &allocationv1.GameServerAllocation{
TypeMeta: metav1.TypeMeta{
APIVersion: "allocation.agones.dev/v1",
Kind: "GameServerAllocation",
},
ObjectMeta: metav1.ObjectMeta{
GenerateName: "allocation-",
Namespace: "default",
},
Spec: allocationv1.GameServerAllocationSpec{
Selectors: []allocationv1.GameServerSelector{{
LabelSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"agones.dev/fleet": "dedicate-server-fleet",
},
},
}},
},
}
// 创建分配请求
created, err := clientset.AllocationV1().GameServerAllocations("default").Create(ctx, allocation, metav1.CreateOptions{})
if err != nil {
return err
}
// 检查分配状态
if created.Status.State == allocationv1.GameServerAllocationAllocated {
gameServerName := created.Status.GameServerName
address := created.Status.Address
// 分配成功
} else if created.Status.State == allocationv1.GameServerAllocationUnAllocated {
// 没有可用的 GameServer,需要重试
}
分配流程:
- match-maker 创建
GameServerAllocationCRD - Agones Allocator 监听到分配请求
- Allocator 从 Fleet 中选择一个 Ready 状态的 GameServer
- Allocator 将 GameServer 状态改为 Allocated
- 返回分配结果(GameServer 名称、地址、端口等)
分配成功后,从 GameServer 的 annotation 获取自定义信息:
gs, _ := clientset.AgonesV1().GameServers(namespace).Get(ctx, gameServerName, metav1.GetOptions{})
publicAddress := gs.Annotations["agones.dev/sdk-public_address"]
注意事项
- 心跳频率 - Health() 调用频率要小于健康检查周期(fleet.yaml 中配置的
periodSeconds) - 优雅关闭 - 收到 SIGTERM 或 WatchGameServer 监听到 Shutdown 状态时,先完成业务逻辑再调用 Shutdown()
- Annotation 前缀 - SetAnnotation 设置的 key 会自动加上
agones.dev/sdk-前缀,读取时要用完整 key