首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探索使用Kubernetes扩展专用游戏服务器:第3部分 - 扩展节点

探索使用Kubernetes扩展专用游戏服务器:第3部分 - 扩展节点

作者头像
为少
发布2021-05-27 18:54:13
6410
发布2021-05-27 18:54:13
举报
文章被收录于专栏:黑客下午茶黑客下午茶

原创科普整理

  • 油管视频:GCAP 2017: Scaling Multiplayer Games with Open Source
    • https://www.youtube.com/watch?v=a08WrvIPKMw
  • Scaling Dedicated Game Servers with Kubernetes: Part 3 – Scaling Up Nodes
    • https://www.compoundtheory.com/scaling-dedicated-game-servers-with-kubernetes-part-3-scaling-up-nodes/
  • 示例项目:paddle-soccer
    • https://github.com/markmandel/paddle-soccer

在前两篇文章中,我们研究了如何在 Kubernetes 上托管专用游戏服务器,并测量和限制其内存和 CPU 资源。在本期中,我们将探讨如何利用上一篇文章中的 CPU 信息来确定何时需要扩展Kubernetes 集群,因为随着玩家人数的增加,我们已经没有足够的空间来容纳更多的游戏服务器。

分离 Apps 和 Game Servers

在开始编写代码以增加 Kubernetes 集群的大小之前,我们应该做的第一步是将我们的应用程序(例如,match makersgame server controllers 和即将编写的 node scaler)分离到不同的应用程序中 一 在集群的不同节点上,而不是游戏服务器运行的地方。

这有几个好处:

  1. 我们的应用程序的资源使用情况现在对游戏服务器没有影响,因为它们在不同的计算机上。这意味着,如果 matchmaker 由于某种原因而导致 CPU 峰值,那么将存在一个额外的障碍,以确保它不会不适当地影响正在运行的专用游戏服务器。
  2. 这使得扩展和缩小专用游戏服务器的容量变得更容易 — 因为我们只需要查看特定节点集的游戏服务器使用情况,而不是整个集群中的所有潜在容器。
  3. 在这种情况下,我们可以使用带有更多 CPU 核和内存的大机器来运行游戏服务器节点,也可以使用带有更少内核和内存的小机器来运行控制器应用程序,因为它们需要的资源更少。我们基本上能够为手头的工作选择合适的机器尺寸。这给了我们很大的灵活性,同时仍然具有成本效益。

Kubernetes 使建立异构集群相对简单,并为我们提供了工具,可通过节点上的节点选择器的功能来指定集群中 Pod 的调度位置。

值得注意的是,beta 中还具有更复杂的 Node Affinity 功能,但是在此示例中我们不需要它,因此我们暂时将其忽略。

首先,我们需要将标签(一组键-值对)分配给集群中的节点。这与您使用 Deployments 创建 Pods 并使用 Services 公开它们时所看到的情况完全相同,只是将其应用于节点。我使用谷歌的云平台的容器引擎和它使用节点池标签应用于集群中的节点创建和建立异构集群——但你也可以做类似的事情在其他云提供商,以及直接通过 Kubernetes API 或命令行客户端。

在本例中,我将标签role:apps和role:game-server添加到集群中的适当节点。然后,我们可以在Kubernetes配置中添加一个nodeSelector选项,以控制集群中的 Pods被调度到哪些节点上面。

例如,下面是 matchmaker 应用程序的配置,您可以看到节点选择器设置为 role:apps,以确保它只在应用程序节点(标记为“apps”角色的节点)上创建容器实例。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: matchmaker
spec:
  replicas: 5
  template:
    metadata:
      labels:
        role: matchmaker-server
    spec:
      nodeSelector:
        role: apps # here is the node selector
      containers:
      - name: matchmaker
        image: gcr.io/soccer/matchmaker
        ports:
        - containerPort: 8080

同样的,我们可以从上一篇文章中调整配置,使所有专用的游戏服务器 pod 调度仅在我们专门为它们指定的机器上,即那些标记为 role: game-server

apiVersion: v1
kind: Pod
metadata:
  generateName: "game-"
spec:
  hostNetwork: true
  restartPolicy: Never
  nodeSelector:
    role: game-server # here is the node selector
  containers:
    - name: soccer-server
      image: gcr.io/soccer/soccer-server:0.1
      env:
        - name: SESSION_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        resources:
          limits:
            cpu: "0.1"

请注意,在示例代码中,使用 Kubernetes API 提供了与上面相同的配置,但 yaml 版本更容易理解,而且它是我们在整个系列中一直使用的格式。

扩大规模的策略

云提供商上的 Kubernetes 往往带有自动伸缩功能,比如谷歌云平台集群自动伸缩器,但由于它们通常是为无状态应用程序构建的,而且我们的专用游戏服务器将游戏模拟存储在内存中,所以它们在这种情况下无法工作。然而,使用 Kubernetes 提供的工具,构建我们自己的定制 Kubernetes 集群自动scaler 并不是特别困难!

对于云环境,在 Kubernetes 集群中扩展和缩小节点可能更有意义,因为我们只想为我们需要/使用的资源付费。如果我们在自己的场所中运行,则更改 Kubernetes 集群的大小可能没什么意义,而且我们可以在所有拥有的机器上运行一个大型集群,并将它们保持为静态大小,因为添加 并且删除物理计算机要比在云上花费更多,并且由于我们拥有/租赁计算机的时间更长,因此不一定能节省我们的钱。

有多种潜在策略可用来确定何时要扩展集群中的节点数量,但是在本示例中,我们将使事情变得相对简单:

  • 定义游戏服务器的最小和最大节点数,并确保我们在该限制之内。
  • 使用 CPU 资源容量和使用率作为我们跟踪集群中一个节点上可以容纳多少专用游戏服务器的指标(在本例中,我们假设我们总是有足够的内存)。
  • 在集群中,为一定数量的游戏服务器定义 CPU 容量缓冲区。也就是说,如果在任何时刻,你都无法在不耗尽集群 CPU 资源的情况下将 n 个服务器添加到集群中,那么就增加更多的节点。
  • 每当启动新的专用游戏服务器时,请计算是否需要在群集中添加新节点,因为跨节点的 CPU 容量低于缓冲区数量。
  • 作为故障保护,每隔 n 秒,还要计算是否需要将新节点添加到群集,因为所测量的 CPU 容量资源在缓冲区下方。

创建 Node Scaler

node scaler 本质上是运行一个事件循环来执行上面概述的策略。

结合使用 Go 和原生 Kubernetes Go client library 库可以相对容易地实现这一点,如下面在节点缩放器的 Start() 函数中所见。

注意,为了使事件循环更清晰,我已经删除了大部分错误处理和其他样板文件,但如果您感兴趣,这里是原始代码。

// Start the HTTP server on the given port
func (s *Server) Start() error {
        
        // Access Kubernetes and return a client
        s.cs, _ = kube.ClientSet()

        // ... there be more code here ... 
        
        // Use the K8s client's watcher channels to see game server events
        gw, _ := s.newGameWatcher()
        gw.start()

        // async loop around either the tick, or the event stream
        // and then scaleNodes() if either occur.
        go func() {
                log.Print("[Info][Start] Starting node scaling...")
                tick := time.Tick(s.tick)

                // ^^^ MAIN EVENT LOOP HERE ^^^
                for {
                        select {
                        case <-gw.events:
                                log.Print("[Info][Scaling] Received Event, Scaling...")
                                s.scaleNodes()                          
                        case <-tick:
                                log.Printf("[Info][Scaling] Tick of %#v, Scaling...", tick)
                                s.scaleNodes()
                        }
                }
        }()
      
        // Start the HTTP server
        return errors.Wrap(s.srv.ListenAndServe(), "Error starting server")
}

对于那些不熟悉 Go 的人,让我们分析一下:

  1. kube.ClientSet() – 我们有一小段实用程序代码,它向我们返回一个 Kubernetes ClientSet,它使我们能够访问正在运行的集群的 Kubernetes API
  2. gw, _ := s.newGameWatcherKubernetes 具有 API,使您可以监视整个集群中的更改。在这种特殊情况下,此处的代码返回一个包含 Go Channel(本质上是一个阻塞队列)的数据结构,特别是 gw.events,每当在集群中添加或删除游戏 Pod 时,该数据结构都将返回一个值。
  3. tick := time.Tick(s.tick) – 这将创建另一个 Go Channel,该 Channel 一直阻塞到给定时间(在这种情况下为10秒),然后返回一个值。
  4. 主事件循环在 “// ^^^ MAIN EVENT LOOP HERE ^^^” 注释下。在此代码块中是一条 select 语句。这实际上声明了系统将阻塞,直到 gw.events channeltick channel(每 10 秒触发一次)返回一个值,然后执行 s.scaleNodes()。这意味着,每当添加/删除游戏服务器或每 10 秒触发一次 scaleNodes 命令。
  5. s.scaleNodes() – 运行上面概述的规模节点策略。

s.scaleNodes() 中,我们通过 Kubernetes API 查询我们在每个 Pod 上设置的 CPU 限制,以及集群中每个 Kubernetes 节点上可用的总 CPU。我们可以通过 Rest APIGo ClientPod specification 中查看已配置的 CPU 限制,这使我们能够跟踪每台游戏服务器占用的 CPU 数量以及任何存在于节点上 Kubernetes 管理的 Pod。通过 Node specificationGo Client 还可以跟踪每个节点中可用的 CPU 容量。在这种情况下,需要对 Pods 占用的 CPU 数量求和,然后从每个节点的容量中减去 CPU 的数量,然后确定是否需要将一个或多个节点添加到集群中,这样我们才能保持该缓冲区空间,用于创建新的游戏服务器。

如果您在此示例中深入研究代码,将会看到我们正在使用 Google Cloud Platform 上的 API 向集群添加新节点。为 Google Compute Engine 托管实例组提供的 API 允许我们从Kubernetes 集群的 Nodepool 中添加(和删除)实例。话虽这么说,任何云提供商都将具有类似的 API,让您做同样的事情,在这里您可以看到我们定义的接口,该接口用于抽象该实现细节,以便可以轻松地对其进行修改以与其他提供商一起使用。

部署节点缩放器

在下面,您可以看到节点缩放器的部署 YAML。如您所见,环境变量用于设置所有配置选项,包括:

  • 集群中的哪些节点应进行管理
  • 每个专用游戏服务器需要多少 CPU
  • 最小和最大节点数
  • 一直存在多少缓冲区
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nodescaler
spec:
  replicas: 1 # only want one, to avoid race conditions
  template:
    metadata:
      labels:
        role: nodescaler-server
    spec:
      nodeSelector:
        role: apps
      strategy:
        type: Recreate
      containers:
      - name: nodescaler
        image: gcr.io/soccer/nodescaler
        env:
          - name: NODE_SELECTOR # the nodes to be managed
            value: "role=game-server"
          - name: CPU_REQUEST # how much CPU each server needs
            value: "0.1"
          - name: BUFFER_COUNT # how many servers do we need buffer for
            value: "30"
          - name: TICK # how often to tick over and recheck everything
            value: "10s"
          - name: MIN_NODE # minimum number of nodes for game servers
            value: "1"
          - name: MAX_NODE # maximum number of nodes for game servers
            value: "15"

您可能已经注意到,我们将部署设置为 replicas: 1。我们这样做的原因是,我们总是希望在Kubernetes 集群中在任何给定的时间点上只有一个活跃的 node scaler 实例。这确保了集群中不会有超过一个进程试图扩大或最终缩小我们的节点,这肯定会导致竞争条件,并可能导致各种奇怪的情况。

同样,如果要更新节点缩放器,要确保在创建节点缩放器之前正确关闭节点缩放器,我们还配置strategy.type: Recreate,以便 Kubernetes 在重新创建节点缩放器之前销毁当前运行的节点缩放器 Pod。更新版本,也避免了任何潜在的竞争情况。

看看它的实际应用

部署节点缩放器后,让我们跟踪日志并查看其运行情况。在下面的视频中,通过日志可以看到,当群集中有一个节点分配给游戏服务器时,我们有能力启动 40 个专用游戏服务器,并配置了 30 个专用游戏服务器的缓冲区的需求。当我们通过 matchmaker 通过运行专用游戏服务器来填充可用的CPU容量时,请注意在剩余空间中可创建的游戏服务器数量会如何下降,最终会添加一个新节点来维护缓冲区!

油管视频:

  • https://www.youtube.com/watch?v=UzIbBZiWsT4
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 黑客下午茶 微信公众号,前往查看

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

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 分离 Apps 和 Game Servers
  • 扩大规模的策略
  • 创建 Node Scaler
  • 部署节点缩放器
  • 看看它的实际应用
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档