Kubernetes与Agones服务缩容优化:如何限制LoadBalancer仅将新流量分发至期望的GameServer副本
解决方案:限制LoadBalancer流量到期望保留的GameServer副本
这确实是Agones结合Kubernetes Deployment缩容时的典型痛点——Agones保护有玩家连接的实例不被终止,但LoadBalancer的无差别流量分发又让多余实例一直有新玩家流入,陷入“关不掉”的死循环。下面是几个可行的方案,结合你的场景(从5个实例缩容到3个)来具体说明:
方案1:利用标签选择器动态控制Service流量范围
这个方案的核心是通过给目标实例打专属标签,让LoadBalancer只匹配带该标签的实例,把新流量完全导向你想保留的3个副本。
操作步骤:
- 标记需要保留的GameServer Pod:
选择你想保留的3个Pod(比如按创建时间最新、当前负载最低等规则),给它们打上专属标签,例如retain: "true":kubectl label pods game-server-xxx-1 game-server-xxx-2 game-server-xxx-3 retain=true - 更新LoadBalancer Service的选择器:
修改Service的spec.selector,在原有GameServer标签(比如app: game-server)基础上,新增对retain: "true"的匹配:apiVersion: v1 kind: Service metadata: name: game-server-lb spec: type: LoadBalancer selector: app: game-server retain: "true" # 新增这个标签匹配 ports: - port: 80 targetPort: game-port - 等待多余实例自然终止:
此时新流量只会分发到带retain=true的3个Pod,另外2个实例没有新玩家接入,等现有玩家全部离开后,Agones会允许它们被Deployment的缩容逻辑终止。 - 恢复Service配置(可选):
缩容完成后,你可以把Service的选择器改回原来的状态,同时去掉保留Pod的retain标签,为下次扩缩容做准备。
优缺点:
- 优点:无需修改现有Deployment/Agones架构,操作简单灵活,适合临时或周期性缩容场景。
- 缺点:需要手动/脚本化标记Pod和更新Service,自动化程度需要额外搭建。
方案2:基于Agones原生状态标签实现流量隔离
Agones的GameServer资源本身会自带agones.dev/state状态标签(比如Ready、Allocated、ShuttingDown等),我们可以利用这个特性,让Service自动排除处于“待关闭”状态的实例。
操作步骤:
- 标记多余实例为待关闭状态:
对需要淘汰的2个GameServer,通过Agones SDK或kubectl设置shutdown: true,触发Agones将其状态切换为ShuttingDown:kubectl patch gameserver game-server-xxx-4 -p '{"spec":{"shutdown":true}}' kubectl patch gameserver game-server-xxx-5 -p '{"spec":{"shutdown":true}}' - 调整Service选择器排除待关闭实例:
修改Service的选择器,过滤掉agones.dev/state为ShuttingDown或Terminating的实例:spec: selector: app: game-server agones.dev/state: "Ready" # 只匹配就绪状态的实例 # 或者用notin语法排除待关闭状态: # agones.dev/state notin (ShuttingDown, Terminating) - 自动完成缩容:
处于ShuttingDown状态的GameServer不会再接收新的玩家分配,等现有玩家断开后,Agones会自动终止这些实例,Deployment的副本数也会逐步降到期望的3个。
优缺点:
- 优点:完全贴合Agones的原生设计,无需额外打标签,状态流转更自动化。
- 缺点:如果你的GameServer是用Deployment管理的(而非Agones原生的GameServerSet),可能需要确保Deployment的缩容逻辑和Agones的状态处理兼容。
方案3:手动/自动化管理Service的Endpoints
LoadBalancer的流量分发本质是基于Kubernetes的Endpoints资源,我们可以直接编辑Endpoints,只保留期望的3个Pod的IP和端口,彻底切断多余实例的流量入口。
操作步骤:
- 获取目标Pod的IP地址:
查询你想保留的3个Pod的IP:RETAIN_IPS=$(kubectl get pods -l app=game-server -o jsonpath='{.items[0:3].status.podIP}' | tr ' ' '\n') - 编辑Endpoints资源:
手动或通过脚本更新Endpoints的subsets.addresses字段,只保留上述IP:
编辑后的Endpoints示例:kubectl edit endpoints game-server-lbapiVersion: v1 kind: Endpoints metadata: name: game-server-lb subsets: - addresses: - ip: 10.0.0.10 # 保留的Pod IP1 - ip: 10.0.0.11 # 保留的Pod IP2 - ip: 10.0.0.12 # 保留的Pod IP3 ports: - port: game-port protocol: TCP
优缺点:
- 优点:直接切断流量,效果立竿见影,适合紧急缩容场景。
- 缺点:Endpoints会被Kubernetes自动同步(如果Service的选择器匹配到Pod),所以需要临时修改Service的选择器为无效值,防止自动覆盖;操作复杂度较高,适合临时应急而非长期自动化。
内容的提问来源于stack exchange,提问作者XLordalX
相关产品推荐
相关产品推荐

