Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >案例分享:使用 Agones 在 TKE 上部署游戏专用服务器

案例分享:使用 Agones 在 TKE 上部署游戏专用服务器

原创
作者头像
imroc
发布于 2025-02-12 03:42:57
发布于 2025-02-12 03:42:57
4340
举报

术语

  • DS:Dedicated Server,游戏专用服务器。在线对战的房间类游戏,同一局的玩家都会连上同一个 DS。本文中的方案采用单 Pod 单房间模式,可以认为一个 DS 就是一个游戏房间。

用户诉求

有一款 PVP(房间类)的游戏基于虚幻引擎 UE5.4 开发,玩家在线匹配到一个房间后,连上同一个 DS 开始进行对战。

具体流程如下。

  1. 首先玩家准备游戏,游戏客户端请求大厅服进行游戏匹配:
  1. 大厅服对玩家进行匹配,匹配成功后,大厅服会根据玩家所选地图、游戏模式和最终匹配人数等条件筛选出符合条件的 DS,将选中的 DS 标记为已分配并下发玩家信息,让 DS 加载:
  1. 等 DS 加载完玩家信息后,大厅服通知游戏客户端开始游戏并提供 DS 公网地址:
  1. 客户端拿到 DS 地址后就可以连上 DS,玩家开始对战:

核心诉求:

  1. 玩家同时在线数量可能暴涨或暴跌,需支持 DS 的动态扩缩容,且扩容速度要快,避免玩家等待过久。
  2. 每个 DS 都需要独立的公网地址,且 DS 数量可能较大,需要支持大规模动态分配公网地址的能力。
  3. 被分配的 DS 不能被再次被分配,缩容时也不允许已分配的 DS 被销毁,避免玩家中断。

初步选型

围绕 DS 有类似 GameLift 这样专门对 DS 进行部署与弹性伸缩云服务,但价格相对较高,灵活性较低,为降低成本和提升灵活性,业务团队决定基于云厂商的托管 Kubernetes云原生游戏开源项目来部署 DS,并配置根据空闲房间数量和比例的自动扩缩容。

托管 Kubernetes 选型

TKE 是腾讯云上托管 Kubernetes 集群的服务,支持超级节点这种 Serverless 形态,每个 Pod 独占轻量虚拟机,既能避免 DS 间相互干扰(强隔离),也能实现快速扩容 Pod(Pod 独占轻量虚机,无需扩容节点)。

Pod 销毁立即自动停止计费,即能保证隔离性和扩容速度,又能按需使用,降低成本,所以托管 Kubernetes 服务选择了 TKE。

工作负载选型

集群选择了 TKE,接下来就是要确定用什么工作负载类型来部署 DS 了。

Kubernetes 自带了 Deployment 和 StatefulSet 两种工作负载类型,但对游戏 DS 来说,都太简陋了。它们都无法做到标识 Pod 中的房间是否空闲,缩容的时候,非空闲的 Pod 可能会被删除,影响正在对战的玩家。

OpenKruiseGame 作为 OpenKruise 项目中的一部分,也是 CNCF 的孵化项目,提供了专门针对游戏场景的 GameServerSet 工作负载,支持通过 自定义服务质量 的方式自动设置 Pod 关联的 GameServer 的扩展状态,比如增加一个名为 idle 的状态,容器内提供探测脚本,根据探测结果自动设置 GameServer 的 idle 状态,并当 idle 为 true 时,自动将 opsState 设为 WaitToBeDeleted,以便在缩容时先缩空闲的 Pod,避免影响正在对战的玩家。

但经深入研究,发现存在一些问题:

  1. OpenKruiseGame 的弹性伸缩基于 KEDA,而 KEDA 最终也是依赖 Kubernetes 的 HPA 进行的弹性伸缩,HPA 在缩容时,会将 Pod 副本数降至 HPA 计算出来的期望副本数,这意味着无法绝对保证所有空闲 Pod 都不被缩容,只能做到优先缩容非空闲 Pod,还需结合合理的配置才能尽可能保证空闲 Pod 不被缩容。
  2. 这个自定义的 idle 状态始终是异步的,当 Pod/DS 已被分配,但 idle 状态还没来得及更新,恰好又正在缩容时,可能导致已被分配且即将开始对战的游戏房间被销毁。虽然可以通过调大 terminationGracePeriodSeconds + 实现优雅终止来尽量降低影响,但着实不太优雅。
  3. 对于游戏匹配,OpenKruiseGame 并未提供分配 GamesServer 的接口。虽然有提供 OpenMatch 的 director kruise-game-open-match-director,可以实现基于 OpenMatch 的游戏匹配(自动将被分配过的 GameServer 的 opsState 置为 Allocated,避免被再次分配和缩容被删除),但由于 OpenMatch 并不能满足业务需求,自研了一套游戏匹配逻辑,所以这个 direcotr 也用不上,需要自行实现 OpenKruiseGame 的 GameServer 分配和管理逻辑才能适配。
  4. 游戏基于虚幻引擎开发,而 OpenKruiseGame 并未提供游戏引擎SDK,要实现业务层面的健康检查、扩展状态和信息管理(如房间里的玩家列表以及玩家信息是否加载完成)等,还是使用 SDK 来的更方便。

根据自身业务情况,基于以上原因,不考虑使用 OpenKruiseGame,转而采用了基于 Agones 来部署 DS。

原因如下:

  1. Agones 提供了各种语言的 SDK 和游戏引擎的插件,当然也包括虚幻引擎,生态很完善,对于开发者来说,让 DS 接入 Kubernetes 很方便。
  2. Agones 天然支持了 GameServer 是否已分配的状态,且提供 GameServerAllocation API 来分配 GameServer,被分配过的 GameServer 的状态自动标记为 Allocated,可以避免被再次分配,更重要的是,可以保证缩容时 Allocated 的 GameServer 一定不会被销毁。
  3. Agones 对自研的游戏匹配模块很友好,直接基于 GameServerAllocation API 来分配 GameServer,减少了很多 GameServer 状态管理的开发成本。

分配游戏房间(DS)的方法

Agones 是单 Pod 单房间的模型,社区也有讨论对单 Pod 多房间的支持,参考 issue #1197,但这会让游戏服的管理很复杂也很难实现,最终只给了个 High Density GameServers 的妥协方案,流程复杂且需要游戏服自己做很大开发工作来适配。

所以还是选择了用单 Pod 单房间的模型进行管理,Agones 提供了 GameServerAllocation API 来分配 GameServer,一个 GameServer 代表一个房间,也代表一个 DS,还支持根据特征(如 label)分配合适的 GameServer,如不同地图、不同 Pod 规格的 GameServer 打上指定的 label,匹配时根据游戏人数和游戏属性(如选择的地图和游戏模式)来匹配到适合的 GameServer。

使用虚幻引擎插件接入 Agones

在游戏项目导入 Agones 插件并启用后,在合适位置初始化 Agones SDK 和调用相关 hook 函数,即可接入 Agones。

Agones 官方提供了 UE5 的插件及其使用方法,参考 Unreal Engine Game Server Client Plugin

使用流水线自动构建容器镜像

使用虚幻引擎开发的游戏,需使用虚幻官方提供的工具进行构建,平时自测一般用虚幻编辑器构建在本地测试,发版时则使用 Coding 流水线来自动构建并编译容器镜像,推送至 TCR 镜像仓库

流水线的大致思路是:

  1. UE 官方提供了 通过命令行构建项目 的方法,可根据自身需求在流水线中编写适合的构建命令。
  2. 假设上一步构建出压缩包名为 LinuxServer.zip,流水线中将其解压到 LinuxServer 文件夹,并使用如下的 Dockerfile 构建容器镜像(注意替换 ENTRYPOINT 中的脚本名称)。
代码语言:dockerfile
AI代码解释
复制
FROM ubuntu:22.04
RUN mkdir /app
COPY ./LinuxServer /app
RUN useradd -m ue5
RUN chown -R ue5:ue5 /app
USER ue5

EXPOSE 7777/tcp
EXPOSE 7777/udp

ENTRYPOINT [ "/app/LyraServer.sh" ]
  1. 最后流水线自动将容器镜像推送到镜像仓库。一般游戏的镜像都较大,就使用腾讯云 TCR 镜像仓库,确保镜像拉取的速度和稳定性。

使用 Agones Fleet 部署

Agones 提供了 Fleet 来编排 DS,也就是一种 Kubernetes 中扩展的自定义工作负载类型,类似 Kubernetes 的 StatefulSet,只是专为游戏场景设计。

Fleet 指定 DS 的副本数,每个副本对应一个 GameServer 对象,该对象中可以记录游戏服务器的状态,如是否已被分配、对外的公网地址、玩家数量等。

Fleet 配置方法参考官方文档 Quickstart: Create a Game Server Fleet

由于游戏中每场对局的人数、地图、游戏模式等业务属性可能不同,所以需要将 Fleet 拆分成多个,不同 Fleet 使用不同 Pod 规格、使用不同启动参数加载不同地图等业务数据,并打上能标识规格、地图等属性的 label,用于后续分配房间(DS)时根据 label 过滤合适的 GameServer。

使用 TKE 网络插件为游戏房间映射公网地址

每个游戏房间(DS)都需要独立的公网地址,而 Agones 只提供了 HostPort 这一种方式,如果用 TKE 超级节点,HostPort 无法使用(因为超级节点是虚拟的节点,HostPort 没有意义)。

TKE 提供了 tke-extend-network-controller 网络插件,可以通过 CLB 端口来为 DS 暴露公网地址,可参考 使用 CLB 为 Pod 分配公网地址映射 进行安装和配置。

如何关联 Agones 的 GameServer 与映射的 CLB IP:Port?可以将 IP:Port 信息写到 GameServer 的 label 中。

下面介绍实现步骤:

  1. 首先定义 DedicatedCLBService 时指定 addressPodAnnotation,即将 CLB 的 IP:Port 信息注入到 Pod 指定注解中:
代码语言:yaml
AI代码解释
复制
apiVersion: networking.cloud.tencent.com/v1alpha1
kind: DedicatedCLBService
metadata:
  namespace: demo
  name: gameserver
spec:
  maxPod: 50
  selector:
    app: gameserver
  ports:
  - protocol: UDP
    targetPort: 9000
    addressPodAnnotation: networking.cloud.tencent.com/external-address # 将外部地址自动注入到指定的 pod annotation 中
  existedLbIds:
    - lb-xxx
  1. 然后定义游戏服工作负载的 pod template 时(Fleet.spec.template.spec.template 字段),利用 downward API 将注解信息挂载到容器中:
代码语言:yaml
AI代码解释
复制
    spec:
      containers:
        - ...
          volumeMounts:
            - name: podinfo
              mountPath: /etc/podinfo
      volumes:
        - name: podinfo
          downwardAPI:
            items:
              - path: "address"
                fieldRef:
                  fieldPath: metadata.annotations['networking.cloud.tencent.com/external-address']
  1. 游戏服启动时轮询此文件,发现内容不为空时即表示 CLB 已绑定好 Pod,内容即为当前房间的公网地址。可通过调用 Agones SDK 的 SetLabel 函数将信息写入到 GameServer 对象中以实现 GameServer 与 CLB 公网地址映射的关联。

架构设计

在游戏业务场景中,游戏房间(DS)不仅有是否分配的状态,还有一些其他业务扩展的状态,比如玩家信息是否加载完成的状态(在玩家匹配成功后,分配一个游戏房间,即 Agones 的 GameServer,但还需等待房间加载完将要连上来的玩家信息后,才通知玩家连接进入房间进行对战)。

考虑到后续还有很多其它游戏要用,就打算不直接在大厅服里写这些房间管理的逻辑,所以引入 room-manager 作为房间管理的中间件,该中间件使用 Go 语言开发,利用 k8s 的 client-go 对集群中的 GameServer 进行 list-watch (其他语言的 k8s SDK 不支持自定义资源的 list-watch),为大厅服暴露两个接口:

  1. 查询 GameServer 信息(从 client-go list-watch 的缓存拿,用于大厅服查询分配的房间是否加载完玩家信息,等加载完就通知玩家连上该房间进行战斗)。
  2. 分配 GameServer (本质上会调用 Agones 提供的 GameServerAllocation API,只是会根据业务需求加一些过滤条件,比如根据匹配的人数、选择的地图和游戏模式等条件匹配满足条件的 GameServer,通过 label 标识和过滤)。

整体流程如下:

弹性伸缩

Agones 支持通过 FleetAutoScaler 声明游戏服的弹性伸缩策略,可以指定 Fleet 预留的 buffer 大小(冗余的空闲房间),可以是数量,也可以是百分比(空闲房间比例):

考虑到 Fleet 众多和游戏规模等因素,希望尽可能控制成本,尽可能精准控制 GameServer 数量,决定设定预留 buffer 大小为指定数量的 GameServer,使用脚本定时修改 buffer 大小,以实现在每日高峰期到来之前提前预留的 GameServer 数量,减少玩家的等待时间;高峰期结束后减小 buffer 数量,降低成本。

参考资料

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
使用 Agones 在 TKE 上部署游戏专用服务器
陈鹏,腾讯云容器服务产品架构师,拥有丰富的云原生技术实践经验,同时也是 Kubernetes、Istio 等云原生项目 Contributor,《Kubernetes 实践指南》等电子书作者。
腾讯云原生
2025/02/05
4370
使用 Agones 在 TKE 上部署游戏专用服务器
游戏服务器的架构演进(完整版)
游戏服务器端,是一个会长期运行的程序,并且它还要服务于多个不定时,不定点的网络请求。所以这类软件的特点是要非常关注稳定性和性能。这类程序如果需要多个协作来提高承载能力,则还要关注部署和扩容的便利性;同时,还需要考虑如何实现某种程度容灾需求。由于多进程协同工作,也带来了开发的复杂度,这也是需要关注的问题。
曲水流觞
2020/07/13
5.7K0
游戏服务器的架构演进(完整版)
可复用的游戏服务器端开发框架之副本系统
在早期的联网游戏中,有两种典型的不同种类,一种是类似《传奇》的全地图,分区分服的MMORPG;另外一种则是类似QQ Game类型的“大厅-开房间”的全区全服游戏。 这两种游戏在底层架构上有非常大的差异。但是,随着网络游戏的发展,在MMORPG中出现了类似开房间的“副本”系统,甚至出现了可以跨服跨区玩的“副本”;而开房间的游戏也离开了简单的UI界面,出现了《地下城勇士》(DNF)这类所有战斗都发生在关卡副本中的游戏。到后来,如《英雄联盟》《星际争霸2》这类复杂的游戏,都渐渐走上了全区全服开房间的架构。因此,本
韩伟
2018/03/05
2.2K0
可复用的游戏服务器端开发框架之副本系统
12 经典游戏服务器端架构概述
现代电子游戏,基本上都会使用一定的网络功能。从验证正版,到多人交互等等,都需要架设一些专用的服务器,以及编写在服务器上的程序。因此,游戏服务器端软件的架构,本质上也是游戏服务器这个特定领域的软件架构。 软件架构的分析,可以通过不同的层面入手。比较经典的软件架构描述,包含了以下几种架构: 1.运行时架构——这种架构关心如何解决运行效率问题,通常以程序进程图、数据流图为表达方式。在大多数开发团队的架构设计文档中,都会包含运行时架构,说明这是一种非常重要的设计方面。这种架构也会显著的影响软件代码的开发效率和部署效率。本文主要讨论的是这种架构。 2.逻辑架构——这种架构关心软件代码之间的关系,主要目的是为了提高软件应对需求变更的便利性。人们往往会以类图、模块图来表达这种架构。这种架构设计在需要长期运营和重用性高的项目中,有至关重要的作用。因为软件的可扩展性和可重用度基本是由这个方面的设计决定的。特别是在游戏领域,需求变更的频繁程度,在多个互联网产业领域里可以说是最高的。本文会涉及一部分这种架构的内容,但不是本文的讨论重点。 3.物理架构——关心软件如何部署,以机房、服务器、网络设备为主要描述对象。 4.数据架构——关心软件涉及的数据结构的设计,对于数据分析挖掘,多系统协作有较大的意义。 5.开发架构——关心软件开发库之间的关系,以及版本管理、开发工具、编译构建的设计,主要为了提高多人协作开发,以及复杂软件库引用的开发效率。现在流行的集成构建系统就是一种开发架构的理论。
范蠡
2018/07/25
8.1K1
12 经典游戏服务器端架构概述
Unity3D-游戏开发移动端网络游戏服务器架构
弱联网的游戏,主要是指对游戏数据实时性要求比较低的联网游戏,比如卡牌游戏,休闲游戏等。
孙寅
2020/06/02
2.5K0
Unity3D-游戏开发移动端网络游戏服务器架构
腾讯游戏K8s应用实践|更贴近业务场景的K8s工作负载:GameDeployment & GameStatefulSet
贺佰元,腾讯高级工程师,硕士毕业于北京邮电大学计算机专业,先后在唯品会和腾讯从事容器和云原生方面的研发工作,有近9年的虚拟化及云计算行业经验,16年开始专注于容器、微服务、云原生平台的研发和设计,目前在腾讯IEG蓝鲸产品中心负责腾讯游戏业务的云原生上云的研发和建设。 引言 蓝鲸容器服务(Blueking Container Service,以下简称BCS)是腾讯 IEG 互动娱乐事业群的容器上云平台,底层基于腾讯云容器服务(Tencent Kubernetes Engine, TKE),为 IEG 的自研
腾讯云原生
2020/12/16
2.6K0
探索使用 Kubernetes 扩展专用游戏服务器:第1部分-容器化和部署
尽管容器(containers)和 Kubernetes 是很酷的技术,但为什么我们要在此平台上运行游戏服务器?
为少
2021/05/27
2.8K0
探索使用 Kubernetes 扩展专用游戏服务器:第1部分-容器化和部署
经典游戏服务器端架构概述 (2)
根据文章内容总结的摘要
韩伟
2016/12/02
5.9K0
经典游戏服务器端架构概述 (2)
Nginx Ingress on TKE 部署最佳实践
开源的 Ingress Controller 的实现使用量最大的莫过于 Nginx Ingress 了,功能强大且性能极高。Nginx Ingress 有多种部署方式,本文将介绍 Nginx Ingress 在 TKE 上的一些部署方案,这几种方案的原理、各自优缺点以及一些选型和使用上的建议。
imroc
2020/08/07
1.4K0
一个人的服务器端
能够做这个MMO的触发点是通过某些途径得到了某个大公司使用的一款3D引擎,其他的都是白手起家。当时大家还不知道有“分布式服务器端”一说,服务器端框架参考了《剑3》:剑3内测的时候经常服务器crash,但是每次只crash一个地图,所以可以推知他们是一个地图一个server;加上自己对服务器端的认识,需要Gate当防火墙,需要GameServer来总管MapServer,需要DB来存储,那么最初的服务器端框架就定下来了:Gate、GameServer、MapServer、DBServer。想让服务器之间的连接方式最简化,所以确定GameServer是中心,其他Server都连接并且只连接GameServer。MapServer和GameServer上面准备加脚本,脚本直接选择了python,因为python语法清晰一点。开发平台选择windows,因为当时公司内没有一个人了解linux。
海哥@开发
2022/04/06
6250
游戏架构上云实战
游戏的分类,按照策划和游戏玩法划分,会有若干个纬度:角色扮演、沙盒竞技、FPS、TPS、休闲舞蹈、音乐社交、SLG、二次元等等,粗略估计有二三十种分类,且无官方准确答案,因为玩法是随着市场需求变化而不断更迭的。
宋永周
2020/08/26
4.4K0
游戏架构上云实战
基于帧同步的游戏框架说明
2,游戏类型是一款在moba游戏上加入rts元素的实时对战游戏,支持1v1,2v2的模式。
用户4766018
2022/11/01
3.2K0
基于帧同步的游戏框架说明
探索使用Kubernetes扩展专用游戏服务器:第2部分-管理CPU和内存
在本系列的第 1 部分中,我们讨论了如何使用专用游戏服务器,将其与 Docker 打包,然后在Kubernetes 上托管和管理它,这是一个很好的开始。然而,由于我们的 Kubernetes 集群通常是固定大小的,我们可能会耗尽所有可用容量来运行我们需要的所有游戏服务器容器,以匹配所有想玩我们的游戏的玩家——这将是一件非常糟糕的事情。
为少
2021/05/27
2.7K0
探索使用Kubernetes扩展专用游戏服务器:第2部分-管理CPU和内存
容器服务 TKE 上服务暴露的几种方式
作者刘飞鸿,腾讯游戏高级工程师,热衷于开源、云计算相关技术。目前主要负责腾讯游戏后台架构设计和运维工作。 预备知识 1. K8S 上 Service 类型 ClusterIP 通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。 NodePort 通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求:,可以从集群的外部访问
腾讯云原生
2020/09/14
2.1K0
腾讯云专家工程师林洁文:如何快速构建一款联机游戏
11月24日,云+社区开发者大会(苏州站)圆满落幕。本次开发者大会的主题为“姑苏城外论技术:物联网·小程序·微服务”,邀请了腾讯内部及业内行业大咖就物联网、小程序、微服务等当前互联网领域的热点技术的落地实践问题进行了深度探讨。同时,各位技术专家也与到场的开发者们展开了开放式对话,精彩不断。下边是林洁文老师关于如何利用小游戏联机对战引擎快速构建一款联机游戏,为游戏提供房间管理、在线匹配、帧同步、状态同步等网络通信服务,帮助开发者快速搭建多人交互游戏的分享。
TVP官方团队
2019/12/03
2.2K0
腾讯云专家工程师林洁文:如何快速构建一款联机游戏
使用 Kubernetes 扩展专用游戏服务器:第4部分-缩减节点
在前三篇文章中,我们将游戏服务器托管在 Kubernetes 上,测量并限制它们的资源使用,并根据使用情况扩大集群中的节点。现在我们需要解决更困难的问题:当资源不再被使用时,缩小集群中的节点,同时确保正在进行的游戏在节点被删除时不会中断。
为少
2021/05/27
7010
使用 Kubernetes 扩展专用游戏服务器:第4部分-缩减节点
【TKE】 平台常见问题 QA
本文章将以 QA 方式记录在使用 TKE 产品过程中的可能会遇到的常见问题解答,将不定期更新。
Jokey
2022/10/09
2.9K0
如何利用状态同步开发一款联机游戏
目前市场上单机游戏占比高,因为相对联机游戏开发周期短、成本低,但联机游戏的社交属性强,玩家粘性高。总体来说,开发联机游戏有一定的技术门槛。
腾讯游戏云
2020/12/24
4.1K0
如何利用状态同步开发一款联机游戏
腾讯云大学大咖分享 | 小游戏联机对战引擎实践
腾讯云大学本期直播课程邀请到了腾讯云Web前端工程师通过两个小游戏demo,讲解了小游戏联机对战引擎中帧同步和状态同步两种应用场景。「腾讯云大学」联合「云加社区」为大家整理了课程精彩干货!
可可爱爱没有脑袋
2019/09/11
4.5K0
腾讯云大学大咖分享 | 小游戏联机对战引擎实践
吴晓斌:"吃鸡"游戏全球多地部署架构分析
“吃鸡”游戏最近十分流行。针对“吃鸡”类游戏在反外挂、加速、安全等方面的需求,腾讯游戏云资深架构师吴晓斌在现场为大家带来了“‘吃鸡’游戏全球多地部署架构分析”的主题分享。
腾讯云开发者社区
2018/01/22
2.2K0
吴晓斌:"吃鸡"游戏全球多地部署架构分析
推荐阅读
相关推荐
使用 Agones 在 TKE 上部署游戏专用服务器
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档