在K8S集群中,如何正确选择工作节点资源大小? 2

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 在K8S集群中,如何正确选择工作节点资源大小?

拉取容器镜像

在Kubernetes中创建Pod时,其定义存储在etcd中。

kubelet的工作是检测到Pod分配给了它的节点并创建它。

kubelet将会:

从控制平面下载定义。


调用容器运行时接口(CRI)来创建Pod的沙箱。CRI会调用容器网络接口(CNI)来将Pod连接到网络。


调用容器存储接口(CSI)来挂载任何容器卷。


在这些步骤结束时,Pod就已经存在了,kubelet可以继续检查活跃性和就绪性探针,并更新控制平面以反映新Pod的状态。


kubelet与CRI、CSI和CNI接口需要注意的是,当CRI在Pod中创建容器时,它必须首先下载容器镜像。


这当然是在当前节点上的容器镜像没有缓存的情况下。


让我们来看一下这如何影响以下两个集群的扩展:


第一个集群有一个4个vCPU和32GB的单一节点。第二个集群有13个1个vCPU和4GB的节点。让我们部署一个使用基于OpenJDK的容器镜像的应用程序,该应用程序使用0.3个vCPU和2GB内存,容器镜像大小为1GB(仅基础镜像大小为775MB)的13个副本。


对这两个集群会发生什么?


在第一个集群中,容器运行时只下载一次镜像并运行13个副本。在第二个集群中,每个容器运行时都会下载并运行镜像。在第一个方案中,只需要下载1GB的镜像。


4191192b5a6bfdf338c05861c661d3ab.png


容器运行时下载一次容器镜像并运行13个副本 然而,在第二个方案中,您需要下载13GB的容器镜像。


由于下载需要时间,第二个集群在创建副本方面比第一个集群要慢。


此外,它会使用更多的带宽并发起更多的请求(即至少每个镜像层一个请求,共计13次),这使得它更容易受到网络故障的影响。


13个容器运行时中的每一个都会下载一个镜像 需要注意的是,这个问题会与集群自动缩放器紧密关联。


bfe7498a507e2a488db08b4988687114.png


如果您的节点较小:


集群自动缩放器会同时配置多个节点。


一旦准备好,每个节点都开始下载容器镜像。


最终,Pod被创建。


当您配置较大的节点时,容器镜像很可能已经在节点上缓存,Pod可以立即开始运行。


1c5626317d8aaa286a7abc8d017c8398.png


想象一下拥有8个节点的集群,每个节点上有一个副本。


6ada27962906e4bc308c90ee93013385.png


最终,Pod会被创建在节点上。


1c5626317d8aaa286a7abc8d017c8398.png


想象一下拥有8个节点的集群,每个节点上有一个副本。


6ada27962906e4bc308c90ee93013385.png



该集群已经满载;将副本扩展到16个会触发集群自动缩放器。


6ff7f06bf325153d77cf9d17a95255b8.png


一旦节点被配置完毕,容器运行时会下载容器镜像。


5bfd07675d46d806afa63158311b64d1.png


最终,Pod会在节点上创建。


所以,您是否应该始终配置较大的节点?


未必如此。


您可以通过容器注册表代理来减轻节点下载相同容器镜像的情况。


在这种情况下,镜像仍然会被下载,但是从当前网络中的本地注册表中下载。


或者您可以使用诸如spegel之类的工具来预热节点的缓存。


使用Spegel,节点是可以广告和共享容器镜像层的对等体。


在这种情况下,容器镜像将从其他工作节点下载,Pod几乎可以立即启动。


但是,容器带宽并不是您必须控制的唯一带宽。


Kubelet与Kubernetes API的扩展


kubelet被设计为从控制平面中获取信息。


因此,在规定的间隔内,kubelet会向Kubernetes API发出请求,以检查集群的状态。


但是控制平面不是会向kubelet发送指令吗?


拉取模型更容易扩展,因为:


控制平面不需要将消息推送到每个工作节点。


节点可以以自己的速度独立地查询API服务器。


控制平面不需要保持与kubelet的连接打开。


请注意,也有显著的例外情况。例如,诸如kubectl logs和kubectl exec之类的命令需要控制平面连接到kubelet(即推送模型)。


但是Kubelet不仅仅是为了查询信息。


它还向主节点报告信息。


例如,kubelet每十秒向集群报告一次节点的状态。


此外,当准备探针失败时(以及应从服务中删除pod端点),kubelet会通知控制平面。


而且kubelet会通过容器指标将控制平面保持更新。


换句话说,kubelet会通过从控制平面发出请求(即从控制平面和向控制平面)来保持节点正常运行所需的状态。


在Kubernetes 1.26及更早版本中,kubelet每秒可以发出多达5个请求(在Kubernetes >1.27中已放宽此限制)。


所以,假设您的kubelet正以最大容量运行(即每秒5个请求),当您运行几个较小的节点与一个单一的大节点时会发生什么?


让我们看看我们的两个集群:


第一个集群有一个4个vCPU和32GB的单一节点。


第二个集群有13个1个vCPU和4GB的节点。


第一个集群生成5个每秒的请求。


一个kubelet每秒发出5个请求


59f8adee9829c5051982fe3d630d1c7e.png


第二个集群每秒发出65个请求(即13 x 5)。


a7008560e5ec78068431d47dfa95ec3d.png


13个kubelet每秒各自发出5个请求


当您运行具有许多较小节点的集群时,您应该将API服务器的扩展性扩展到处理更频繁的请求。


而反过来,这通常意味着在较大的实例上运行控制平面或运行多个控制平面。

节点和集群限制

Kubernetes集群的节点数量是否有限制?


Kubernetes被设计为支持多达5000个节点。


然而,这并不是一个严格的限制,正如Google团队所演示的,允许您在15,000个节点上运行GKE集群。


对于大多数用例来说,5000个节点已经是一个很大的数量,可能不会是影响您决定选择较大还是较小节点的因素。


相反,您可以运行在节点中运行的最大Pod数可能会引导您重新思考集群架构。


那么,在Kubernetes节点中,您可以运行多少个Pod?


大多数云提供商允许您在每个节点上运行110到250个Pod。


如果您自己配置集群,则默认为110。


在大多数情况下,这个数字不是kubelet的限制,而是云提供商对重复预定IP地址的风险的容忍度。


为了理解这是什么意思,让我们退后一步,看看集群网络是如何构建的。


在大多数情况下,每个工作节点都被分配一个具有256个地址的子网(例如10.0.1.0/24)。


bcceb3d34c3c1f9dd926ad52e96b2c49.png


每个工作节点都被分配一个子网


其中两个是受限制的,您可以使用254来运行您的Pods。


考虑这种情况,其中在同一个节点上有254个Pod。


您创建了一个更多的Pod,但已经耗尽了可用的IP地址,它保持在挂起状态。


为了解决这个问题,您决定将副本数减少到253。


那么挂起的Pod会在集群中被创建吗?


可能不会。


当您删除Pod时,其状态会变为“正在终止”。


kubelet向Pod发送SIGTERM信号(以及调用preStop生命周期钩子(如果存在)),并等待容器优雅地关闭。


如果容器在30秒内没有终止,kubelet将发送SIGKILL信号到容器,并强制进程终止。


在此期间,Pod仍未释放IP地址,流量仍然可以到达它。


当Pod最终被删除时,IP地址被释放。


kubelet通知控制平面Pod已成功删除。IP地址终于被释放。


想象一下您的节点正在使用所有可用的IP地址。


当一个Pod被删除时,kubelet会收到变更通知。

e322f02b6cc201e1e7daa567b9e4f7e5.png



如果Pod有一个preStop钩子,首先会调用它。然后,kubelet会向容器发送SIGTERM信号。

d5007c0a1b2ccf13b51c1a20784d9b3c.png



默认情况下,进程有30秒的时间来退出,包括preStop钩子。如果在这之前进程没有退出,kubelet会发送SIGKILL信号,强制终止进程。


cce793f20a6666d1c43f15c3bae14cf6.png


kubelet会通知控制平面Pod已成功删除。IP地址最终被释放。


2f4c0cf48c25e515d3242f53e935731a.png


当一个Pod被删除时,IP地址不会立即释放。您必须等待优雅的关闭。


这是一个好主意吗?


好吧,没有其他可用的IP地址 - 所以您没有选择。


想象一下,您的节点正在使用所有可用的IP地址。


ce8edb5d451cb85fe2b94d59a0c9caf0.png

cd93e85fa60a8d7b06d52ff8819793e6.png



一旦Pod被删除,IP地址就可以被重新使用。


4ce78b4920cde26b77c730a4726f1b3a.png


kubelet通知控制平面Pod已成功删除。IP地址终于被释放。


此时,挂起的Pod可以被创建,并且分配给它与上一个相同的IP地址。


想象一下,您的节点正在使用所有可用的IP地址。


下一页


那后果会怎样?


还记得我们提到过,Pod应该优雅地关闭并处理所有未处理的请求吗?


嗯,如果Pod被突然终止(即没有优雅的关闭),并且IP地址立即分配给另一个Pod,那么所有现有的应用程序和Kubernetes组件可能仍然不知道这个更改。


入口控制器将流量路由到一个IP地址。


92deec0e2763ab41db5df53b5ee21f34.png


如果IP地址在没有等待优雅关闭的情况下被回收并被一个新的Pod使用,入口控制器可能仍然会将流量路由到该IP地址。


b95988ae2a75b06815d2c7e532198238.png


因此,一些现有的流量可能会错误地发送到新的Pod,因为它与旧的Pod具有相同的IP地址。


为了避免这个问题,您可以分配较少的IP地址(例如110)并使用剩余的IP地址作为缓冲区。


这样,您可以相当肯定地确保不会立即重新使用相同的IP地址。


存储

计算单元对可以附加的磁盘数量有限制。


例如,在Azure上,具有2个vCPU和8GB内存的Standard_D2_v5实例最多可以附加4个数据磁盘。


如果您希望将StatefulSet部署到使用Standard_D2_v5实例类型的工作节点上,您将无法创建超过四个副本。


这是因为StatefulSet中的每个副本都附加有一个磁盘。


一旦创建第五个副本,Pod将保持挂起状态,因为无法将持久卷声明绑定到持久卷。


为什么呢?


因为每个持久卷都是一个附加的磁盘,所以您在该实例中只能有4个。


那么,您有哪些选择?


您可以提供一个更大的实例。


或者您可以使用不同的子路径字段重新使用相同的磁盘。


让我们看一个例子。


下面的持久卷需要一个具有16GB空间的磁盘:


如果您将此资源提交到集群,您将看到创建了一个持久卷并绑定到它。


$ kubectl get pv,pvc

持久卷与持久卷声明之间存在一对一的关系,因此您无法有更多的持久卷声明来使用相同的磁盘。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
spec:
  selector:
    matchLabels:
      name: app1
  template:
    metadata:
      labels:
        name: app1
    spec:
      volumes:
        - name: pv-storage
          persistentVolumeClaim:
            claimName: shared
      containers:
        - name: main
          image: busybox
          volumeMounts:
            - mountPath: '/data'
              name: pv-storage


如果您想在您的Pod中使用该声明,可以这样做:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app2
spec:
  selector:
    matchLabels:
      name: app2
  template:
    metadata:
      labels:
        name: app2
    spec:
      volumes:
        - name: pv-storage
          persistentVolumeClaim:
            claimName: shared
      containers:
        - name: main
          image: busybox
          volumeMounts:
            - mountPath: '/data'
              name: pv-storage


您可以有另一个使用相同持久卷声明的部署:


但是,通过这种配置,两个Pod将在同一个文件夹中写入其数据。


您可以通过在subPath中使用子目录来解决此问题。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app2
spec:
  selector:
    matchLabels:
      name: app2
  template:
    metadata:
      labels:
        name: app2
    spec:
      volumes:
        - name: pv-storage
          persistentVolumeClaim:
            claimName: shared
      containers:
        - name: main
          image: busybox
          volumeMounts:
            - mountPath: '/data'
              name: pv-storage


subPath: app2

部署将在以下路径上写入其数据:


对于第一个部署,是/data/app1


对于第二个部署,是/data/app2


这个解决方法并不是完美的,有一些限制:


所有部署都必须记住使用subPath。如果需要写入卷,您应该选择可以从多个节点访问的Read-Write-Many卷。这些通常需要昂贵的提供。此外,对于StatefulSet,相同的解决方法无法起作用,因为这将为每个副本创建全新的持久卷声明(和持久卷)。


总结和结论

那么,在集群中是使用少量大节点还是许多小节点?


这取决于情况。


反正,什么是小的,什么是大的?


这取决于您在集群中部署的工作负载。


例如,如果您的应用程序需要10GB内存,那么运行一个具有16GB内存的实例等于“运行一个较小的节点”。


对于只需要64MB内存的应用程序来说,相同的实例可能被认为是“大的”,因为您可以容纳多个这样的实例。


那么,对于具有不同资源需求的混合工作负载呢?


在Kubernetes中,没有规定所有节点必须具有相同的大小。


您完全可以在集群中使用不同大小的节点混合。


这可能让您在这两种方法的优缺点之间进行权衡。


虽然您可能会通过试错来找到答案,但我们还开发了一个工具来帮助您进行这个过程。


Kubernetes实例计算器可以让您探索适用于特定工作负载的最佳实例类型。


确保您尝试一下这个工具。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
ACK One 的多集群应用分发,可以最小成本地结合您已有的单集群 CD 系统,无需对原先应用资源 YAML 进行修改,即可快速构建成多集群的 CD 系统,并同时获得强大的多集群资源调度和分发的能力。
64 9
|
1月前
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
本文介绍如何利用阿里云的分布式云容器平台ACK One的多集群应用分发功能,结合云效CD能力,快速将单集群CD系统升级为多集群CD系统。通过增加分发策略(PropagationPolicy)和差异化策略(OverridePolicy),并修改单集群kubeconfig为舰队kubeconfig,可实现无损改造。该方案具备多地域多集群智能资源调度、重调度及故障迁移等能力,帮助用户提升业务效率与可靠性。
|
3月前
|
存储 Kubernetes 监控
K8s集群实战:使用kubeadm和kuboard部署Kubernetes集群
总之,使用kubeadm和kuboard部署K8s集群就像回归童年一样,简单又有趣。不要忘记,技术是为人服务的,用K8s集群操控云端资源,我们不过是想在复杂的世界找寻简单。尽管部署过程可能遇到困难,但朝着简化复杂的目标,我们就能找到意义和乐趣。希望你也能利用这些工具,找到你的乐趣,满足你的需求。
285 33
|
3月前
|
Kubernetes 开发者 Docker
集群部署:使用Rancher部署Kubernetes集群。
以上就是使用 Rancher 部署 Kubernetes 集群的流程。使用 Rancher 和 Kubernetes,开发者可以受益于灵活性和可扩展性,允许他们在多种环境中运行多种应用,同时利用自动化工具使工作负载更加高效。
154 19
|
3月前
|
人工智能 分布式计算 调度
打破资源边界、告别资源浪费:ACK One 多集群Spark和AI作业调度
ACK One多集群Spark作业调度,可以帮助您在不影响集群中正在运行的在线业务的前提下,打破资源边界,根据各集群实际剩余资源来进行调度,最大化您多集群中闲置资源的利用率。
|
3月前
|
Kubernetes API 网络安全
当node节点kubectl 命令无法连接到 Kubernetes API 服务器
当Node节点上的 `kubectl`无法连接到Kubernetes API服务器时,可以通过以上步骤逐步排查和解决问题。首先确保网络连接正常,验证 `kubeconfig`文件配置正确,检查API服务器和Node节点的状态,最后排除防火墙或网络策略的干扰,并通过重启服务恢复正常连接。通过这些措施,可以有效解决与Kubernetes API服务器通信的常见问题,从而保障集群的正常运行。
236 17
|
3月前
|
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停止抓包。
114 12
|
4月前
|
存储 Kubernetes 对象存储
部署DeepSeek但GPU不足,ACK One注册集群助力解决IDC GPU资源不足
部署DeepSeek但GPU不足,ACK One注册集群助力解决IDC GPU资源不足
117 3
|
3月前
|
Prometheus Kubernetes 监控
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
128 0
OpenAI故障复盘丨如何保障大规模K8s集群稳定性
|
4月前
|
弹性计算 运维 Kubernetes
使用ACK Edge统一管理多地域的ECS资源
使用ACK Edge统一管理多地域的ECS资源

推荐镜像

更多
下一篇
oss创建bucket