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

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
2月前
|
Kubernetes API 调度
k8s中节点无法启动Pod
【10月更文挑战第3天】
119 6
|
11天前
|
弹性计算 调度 数据中心
阿里云 ACK One 注册集群云上弹性:扩展业务新利器
随着企业数字化转型深入,传统IDC数据中心因物理容量限制,难以实现动态扩容,缺乏弹性能力。阿里云ACK One注册集群凭借其高度灵活性和丰富资源选择,成为解决此问题的最佳方案。通过与阿里云资源的整合,ACK One不仅实现了计算资源的按需扩展,提高了资源利用率,还通过按需付费模式降低了成本,使企业能够更高效地应对业务增长和高峰需求。
|
21天前
|
机器学习/深度学习 JavaScript Cloud Native
Node.js作为一种快速、可扩展的服务器端运行时环境
Node.js作为一种快速、可扩展的服务器端运行时环境
33 8
|
2月前
|
Prometheus Kubernetes 监控
k8s部署针对外部服务器的prometheus服务
通过上述步骤,您不仅成功地在Kubernetes集群内部署了Prometheus,还实现了对集群外服务器的有效监控。理解并实施网络配置是关键,确保监控数据的准确无误传输。随着监控需求的增长,您还可以进一步探索Prometheus生态中的其他组件,如Alertmanager、Grafana等,以构建完整的监控与报警体系。
135 60
|
2月前
|
Prometheus Kubernetes 监控
k8s部署针对外部服务器的prometheus服务
通过上述步骤,您不仅成功地在Kubernetes集群内部署了Prometheus,还实现了对集群外服务器的有效监控。理解并实施网络配置是关键,确保监控数据的准确无误传输。随着监控需求的增长,您还可以进一步探索Prometheus生态中的其他组件,如Alertmanager、Grafana等,以构建完整的监控与报警体系。
269 62
|
27天前
|
Prometheus Kubernetes 监控
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
深入探索Kubernetes中的Pod自动扩展(Horizontal Pod Autoscaler, HPA)
|
2月前
|
分布式计算 Hadoop Shell
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
Hadoop-35 HBase 集群配置和启动 3节点云服务器 集群效果测试 Shell测试
80 4
|
2月前
|
XML 分布式计算 资源调度
大数据-02-Hadoop集群 XML配置 超详细 core-site.xml hdfs-site.xml 3节点云服务器 2C4G HDFS Yarn MapRedece(一)
大数据-02-Hadoop集群 XML配置 超详细 core-site.xml hdfs-site.xml 3节点云服务器 2C4G HDFS Yarn MapRedece(一)
182 5
|
2月前
|
分布式计算 Hadoop Shell
Hadoop-36 HBase 3节点云服务器集群 HBase Shell 增删改查 全程多图详细 列族 row key value filter
Hadoop-36 HBase 3节点云服务器集群 HBase Shell 增删改查 全程多图详细 列族 row key value filter
60 3