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

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

在前两篇文章中,我们研究了如何在 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被调度到哪些节点上面。

image.gif

例如,下面是 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 容量资源在缓冲区下方。


微信图片_20220611154641.png

创建 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容量时,请注意在剩余空间中可创建的游戏服务器数量会如何下降,最终会添加一个新节点来维护缓冲区!

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
5月前
|
安全 数据可视化 Linux
在线游戏的地基:VPS和专用服务器性价比大比拼!
游戏服务器是在线游戏的基石,选择合适的服务器类型对玩家体验至关重要。本文对比了VPS(虚拟专用服务器)和专用服务器的优劣势:VPS经济灵活、易于管理,但性能和安全存在局限,适合预算有限或玩家规模适中的游戏;专用服务器性能强大、安全可靠且可控性高,但成本和技术门槛较高,更适合大型MMO或竞技游戏。根据游戏类型、预算、技术能力和扩展需求,合理选择服务器类型是关键。初创阶段可选用中端VPS,成长阶段考虑高端VPS或低端专用服务器,成熟阶段则需高端专用服务器集群。未来,混合架构或将实现性能与成本的平衡。最终,以玩家流畅体验为导向,选择最适合的服务器方案。
197 3
|
8月前
|
Kubernetes API 网络安全
当node节点kubectl 命令无法连接到 Kubernetes API 服务器
当Node节点上的 `kubectl`无法连接到Kubernetes API服务器时,可以通过以上步骤逐步排查和解决问题。首先确保网络连接正常,验证 `kubeconfig`文件配置正确,检查API服务器和Node节点的状态,最后排除防火墙或网络策略的干扰,并通过重启服务恢复正常连接。通过这些措施,可以有效解决与Kubernetes API服务器通信的常见问题,从而保障集群的正常运行。
610 17
|
12月前
|
Prometheus Kubernetes 监控
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
|
8月前
|
Kubernetes Shell Windows
【Azure K8S | AKS】在AKS的节点中抓取目标POD的网络包方法分享
在AKS中遇到复杂网络问题时,可通过以下步骤进入特定POD抓取网络包进行分析:1. 使用`kubectl get pods`确认Pod所在Node;2. 通过`kubectl node-shell`登录Node;3. 使用`crictl ps`找到Pod的Container ID;4. 获取PID并使用`nsenter`进入Pod的网络空间;5. 在`/var/tmp`目录下使用`tcpdump`抓包。完成后按Ctrl+C停止抓包。
287 12
|
9月前
|
Kubernetes 监控 Serverless
基于阿里云Serverless Kubernetes(ASK)的无服务器架构设计与实践
无服务器架构(Serverless Architecture)在云原生技术中备受关注,开发者只需专注于业务逻辑,无需管理服务器。阿里云Serverless Kubernetes(ASK)是基于Kubernetes的托管服务,提供极致弹性和按需付费能力。本文深入探讨如何使用ASK设计和实现无服务器架构,涵盖事件驱动、自动扩展、无状态设计、监控与日志及成本优化等方面,并通过图片处理服务案例展示具体实践,帮助构建高效可靠的无服务器应用。
|
11月前
|
弹性计算 调度 数据中心
阿里云 ACK One 注册集群云上弹性:扩展业务新利器
随着企业数字化转型深入,传统IDC数据中心因物理容量限制,难以实现动态扩容,缺乏弹性能力。阿里云ACK One注册集群凭借其高度灵活性和丰富资源选择,成为解决此问题的最佳方案。通过与阿里云资源的整合,ACK One不仅实现了计算资源的按需扩展,提高了资源利用率,还通过按需付费模式降低了成本,使企业能够更高效地应对业务增长和高峰需求。
|
11月前
|
机器学习/深度学习 JavaScript Cloud Native
Node.js作为一种快速、可扩展的服务器端运行时环境
Node.js作为一种快速、可扩展的服务器端运行时环境
198 8

热门文章

最新文章

推荐镜像

更多