草庐IT

kubernetes之资源限制及QOS服务质量

海棠 2023-03-28 原文

1.什么是资源限制?

1.1在kubernetes集群中,为了使得系统能够稳定的运行,通常会对Pod的资源使用量进行限制。在kubernetes集群中,如果有一个程序出现异常,并且占用大量的系统资源,如果没有对该Pod进行资源限制的话,可能会影响其他的Pod正常运行,从而造成业务的不稳定性。

1.2正常情况下我们在一个宿主机的内核之上,这个宿主机可能管理了一组硬件包括CPU、内存。而后在这个宿主机的内核之上,我们可以运行多个容器,这些容器将共享底层的同一个内核,很显然,硬件是属于内核的,因此任何容器中的每一个进程默认可以请求占有这个内核管理的所有的可用硬件资源。
1.3尤其是多租户的环境当中,有人恶意的运行了一个容器,这个容器可能会大量的占用CPU和内存,进而会导致其他容器无法运行,Docker容器启动的时候默认是在内核的名称空间级别进行了隔离,在进程所运行的资源范围上并没有做太多的隔离操作。我们应该为每个应用设定内部进程运行最为合理的资源的最小保证量和最大保证量。
1.4官方文档:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-cpu-resource/

2.如何实现资源限制?

  • kubernetes通过Requests和Limits字段来实现对Pod的资源限制;
  • Requests: 启动Pod时申请分配的资源大小,即容器运行可能用不到这些额度的资源,但用到时必须确保有这么多的资源使用;(Pod在调度的时候requests比较重要)
  • Limits: 限制Pod运行最大的可用的资源大小,即硬限制;(Pod在运行时limits比较重要)
  • 相比较来说,CPU属于可压缩(compressible)资源,即资源额度可按需收缩,而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度上的问题,如果超载,所有Pod内存加起来超过节点就会触发OOM机制,杀死Pod,具体杀死哪个Pod,就要看QOS服务质量。优先把评分低的杀掉;
  • 正常情况下,Resources可以定义在Pod上也可以定义在Containers上。定义在Pod上是对Pod上所有容器都生效。一般而言我们定义资源是明确定义在每个容器上的,因为不同容器之间可能需求是不一样的。
spec.containers[].resources.request.cpu     # Pod申请时的CPU,如果节点没有足够大,则Pod调度失败
spec.containers[].resources.request.memory  # Pod申请时的内存
spec.containers[].resource.limits.cpu       # Pod最大可使用的CPU
spec.containers[].resource.limits.memory    # Pod最大可使用的内存

3.资源限制的目的

3.1我们为什么要进行资源限制?

  • CPU: 为集群中运行的容器配置CPU请求和限制,可以有效的利用集群上可用的CPU资源;
    设置Pod CPU请求,设置在较低的数值,可以使得Pod更有机会被调度节点;
    通过设置CPU限制大于CPU请求,可以完成两件事:
    1.当Pod碰到一些突发负载时,它可以合理利用可用的CPU资源。
    2.当Pod在突发流量期间,可使用的CPU被限制为合理的值,从而可用避免影响其他Pod的正常运行;
  • memory: 为集群中运行的容器配置内存请求和限制,可以有效利用集群节点上的可以的内存资源;
    通过将Pod的内存请求设定在较低的数值,可以有效的利用节点上可用的内存资源。通过让内存限制大于内存请求,可以完成如下:
    1.当Pod碰到突发请求,可以更好的利用其主机上的可用内存;
    2.当Pod在突发负载期间可使用的内存被限制为合理的数值,从而可用避免影响其他Pod的运行;

4.资源限制单位

4.1CPU限制单位
1核CPU=1000毫核,当定义容器为0.5时,所需要的CPU资源是1核心CPU的一般,对于CPU单位,表达式0.1等价于表达式100m,可以看作是100millicpu;

1核=1000millicpu (1 Core=1000m)
0.5核=500millicpu  (0.5 Core=500m)

4.2内存限制单位
内存的基本单位是字节数(Bytes),也可以使用E、P、T、G、M、K作为单位后缀,或Ei、Pi、Ti、Gi、Mi和Ki形式单位后缀;

1MB=1000KB=1000000Bytes
1Mi=1024KB=1048576Bytes

5.资源限制配置案例

5.1CPU配置;

5.1.1设置容器的CPU请求与限制;

需安装Metrics-Server才能用top命令否则无法使用;

没有metrics-server会报错error: Metrics API not available
# 创建一个具有一个容器的Pod,容器将请求0.5个CPU,最多限制1个CPU;
root@kubernetes-master01:~# cat cpu-requests-limits.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: cpu-test-cpu-limits
spec:
  containers:
  - name: cpu-test-stress
    image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
    args:
    - -cpus         # 容器尝试使用2核CPU
    - "2"
    resources:
       requests:  #  限制Pod最多可申请0.5核CPU
         cpu: "500m"  
       limits:     # 限制Pod最大可使用1核CPU
         cpu: "1000m"
root@kubernetes-master01:~# kubectl apply -f cpu-requests-limits.yaml 
pod/cpu-test-cpu-limits created

# 查看资源限制情况,容器配置去尝试使用2个CPU,但是容器只能被允许使用1个CPU;
root@kubernetes-master01:~# kubectl top pods cpu-test-cpu-limits
NAME                  CPU(cores)   MEMORY(bytes)   
cpu-test-cpu-limits   999m        1Mi    

5.1.2创建一个Pod,设置该Pod中容器请求为100核,这个值会大于集群中所有内存的总和;

root@kubernetes-master01:~# cat cpu-requests-limits.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: cpu-test-cpu-limits
spec:
  containers:
  - name: cpu-demo-ctr
    image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
    args:
    - -cpus
    - "2"
    resources:
       requests:
         cpu: "100"   # 设置Pod申请100GB,我们集群上没有100GB的资源
       limits:
         cpu: "100"   # 最大使用100GB,集群资源不足,无法创建;
root@kubernetes-master01:~# kubectl apply -f cpu-requests-limits.yaml 
pod/cpu-test-cpu-limits created

# 查看Pod的状态,为Pending,Pod未被调度到任何节点上;
root@kubernetes-master01:~# kubectl get pods
cpu-test-cpu-limits                          0/1     Pending   0          4s

# 查看Events,输出显示由于3节点的CPU资源不足,无法进行调度;
root@kubernetes-master01:~# kubectl describe pods cpu-test-cpu-limits
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  113s  default-scheduler  0/3 nodes are available: 3 Insufficient cpu.
  Warning  FailedScheduling  113s  default-scheduler  0/3 nodes are available: 3 Insufficient cpu.

5.1.3如果不指定CPU的Limits?
如果没有为容器配置CPU限制,那么容器在可以使用的CPU资源是没有上限的,因而可以使用所在节点上的所有可用CPU资源,这样会造成某一个Pod占用了大量的CPU,可能会影响其他Pod的正常允许,从而造成业务的不稳定性。

5.2内存配置;

5.2.1设置容器的内存请求与限制;
创建一个1个容器Pod,容器会将请求100MB内存,并且最大可用内存为200MB以内;

root@kubernetes-master01:~# cat memory-requests-limits.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-memory-resource
spec:
  containers:
  - name: momory-demo-stress
    image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1" ]
    resources:
      requests:
        memory: "100Mi"   # 设置最小请求为100Mi
      limits:
        memory: "200Mi"   # 最大可使用200Mi
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml 
pod/pod-memory-resource created

# 获取Pod的内存使用信息,输出结果显示Pod正在使用的内存约为150Mi,大于Pod请求的100Mi,但是在Pod限制的200Mi之内。
root@kubernetes-master01:~# kubectl top po pod-memory-resource
NAME                  CPU(cores)   MEMORY(bytes)   
pod-memory-resource   43m          151Mi 

# 也可用通过Yaml文件的方式来看limits最大可使用为200Mi
    resources:
      limits:
        memory: 200Mi
      requests:
        memory: 100Mi

5.2.2运行超过容器内存限制的应用
当节点拥有足够的可用内存时,容器可用使用其请求的内存,但是,容器不允许使用超过其限制的内存。如果容器分配的内存超过其限制,该容器会成为被终止的候选容器。如果容器继续消耗超过其限制的内存,则终止容器。如果终止的容器可以被重启,则kubelet会重新启动它。

5.2.2.1创建一个Pod,拥有一个Containers,该容器的内存请求为100Mi,内存限制为200Mi,尝试分配超出其限制的内存;

root@kubernetes-master01:~# cat memory-requests-limits.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-memory-resource
spec:
  containers:
  - name: momory-demo-ctr
    image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1" ]  # 强行分配250M
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"  # 我们上限不能超过200,超过200Mi会发生OOM Kill
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml

# 查看Pod,此时容器被杀死;
root@kubernetes-master01:~# kubectl get pods -w
pod-memory-resource                          0/1     OOMKilled           0          9s
pod-memory-resource                          0/1     OOMKilled           1          11s
pod-memory-resource                          0/1     CrashLoopBackOff    1          12s

# 查看更详细的信息,显示为OOMKilled;
root@kubernetes-master01:~#kubectl get  pod pod-memory-resource -o yaml
 lastState:
      terminated:
        containerID: docker://3d6e53a12a101f474d24c00b8e9c5b1e6da2ef26735b6e2cb6790184c6d69cfa
        exitCode: 1
        finishedAt: "2022-07-27T06:40:07Z"
        reason: OOMKilled

5.2.3超过节点的内存分配
Pod的调度基于请求,只有当前节点拥有足够满足Pod内存请求的内存时,才会将Pod调度至该节点运行;
5.2.3.1创建一个Pod,其拥有一个请求1000GB内存的容器,超出了集群任何一个节点所拥有的内存;

root@kubernetes-master01:~/cloud-Native/resource# cat memory-requests-limits.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-memory-resource
spec:
  containers:
  - name: momory-demo-ctr
    image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1" ]
    resources:
      requests:
        memory: "100Gi"
      limits:
        memory: "200Gi"
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml

# 查看Pod状态,发现处于pending,这意味着该Pod未被调度至任何节点;
root@kubernetes-master01:~# kubectl get pods -w
pod-memory-resource                          0/1     Pending   0          6s

# 通过describe查看更详细信息;显示为由于节点内存不足,该容器无法被调度;
root@kubernetes-master01:~# kubectl describe pods pod-memory-resource
Events:
  Type     Reason            Age    From               Message
  ----     ------            ----   ----               -------
  Warning  FailedScheduling  2m21s  default-scheduler  0/3 nodes are available: 3 Insufficient memory.
  Warning  FailedScheduling  2m20s  default-scheduler  0/3 nodes are available: 3 Insufficient memory.

5.2.4如果没有指定内存限制;
如果为容器指定内存限制,容器可以无限的使用其所在节点的所有可用内存,进而可能导致该节点调用OOM Killer。此外如果发生OOM Kill,没有配置资源限制的容器将被杀死的可能性会更大。

6.QOS服务质量

6.1什么是QOS?

kubernetes允许节点资源对limits的过载使用,这意味着节点无法同时满足其上的所有Pod对象以资源满载的方式运行,于是在内存资源紧缺时,应该以何种次序先后终止哪些Pod对象?
kubernetes无法自行对此做出决策,它需要借助于Pod对象的优先级判定,根据Pod对象的Requests和Limits属性,kubernetes将Pod对象归类到BestEffort、Burstable和Guaranteed三个服务质量(Quality of Service,QOS);
6.1.1Guaranteed: Pod对象为每个容器都设置了CPU资源需求和资源限制,且两者的值相同,还同时为每个容器设置了内存需求与内存限制,并且两者的值相同,这类Pod对象具有最高级别服务质量。
6.1.2Burstable: 至少有一个容器设置了CPU或内存资源Requests属性,但不满足Guaranteed,这类Pod具有中级服务质量;
6.1.3BestEffort: 没有为任何容器设置Requests和Limits属性,这类Pod对象服务质量是最低级别。

1.当kubernetes集群内存资源紧缺,优先杀死BestEffort类别的容器,因为系统不为该类资源提供任何服务保证,但是此类资源最大的好处就是能够尽可能的使用资源。
2.如果系统中没有BestEffort类别的容器,接下来就轮到Burstable类别的容器,如果有多个Burstable类别的容器,就看谁的资源占用多就优先杀死谁。对于Guaranteed类别的容器拥有最高优先级,他们不会被杀死,除非其内存需求超限,或OMM时没有其他更低优先级的Pod对象存在,才干掉Guaranteed类容器;

有关kubernetes之资源限制及QOS服务质量的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  4. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  5. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

  6. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  7. ruby - 我的 Ruby IRC 机器人没有连接到 IRC 服务器。我究竟做错了什么? - 2

    require"socket"server="irc.rizon.net"port="6667"nick="RubyIRCBot"channel="#0x40"s=TCPSocket.open(server,port)s.print("USERTesting",0)s.print("NICK#{nick}",0)s.print("JOIN#{channel}",0)这个IRC机器人没有连接到IRC服务器,我做错了什么? 最佳答案 失败并显示此消息::irc.shakeababy.net461*USER:Notenoughparame

  8. ruby - Rails 开发服务器、PDFKit 和多线程 - 2

    我有一个使用PDFKit呈现网页的pdf版本的Rails应用程序。我使用Thin作为开发服务器。问题是当我处于开发模式时。当我使用“bundleexecrailss”启动我的服务器并尝试呈现任何PDF时,整个过程会陷入僵局,因为当您呈现PDF时,会向服务器请求一些额外的资源,如图像和css,看起来只有一个线程.如何配置Rails开发服务器以运行多个工作线程?非常感谢。 最佳答案 我找到的最简单的解决方案是unicorn.geminstallunicorn创建一个unicorn.conf:worker_processes3然后使用它:

  9. ruby - Dropbox 类似 git 的服务——没有 rsync 和 inotify - 2

    关于如何使用git设置类似Dropbox的服务,您有什么建议吗?您认为git是解决此问题的合适工具吗?我在考虑使用git+rush解决方案,你觉得怎么样? 最佳答案 检查这个开源项目:https://github.com/hbons/SparkleShare来自项目的自述文件:Howdoesitwork?SparkleSharecreatesaspecialfolderonyourcomputer.Youcanaddremotelyhostedfolders(or"projects")tothisfolder.Theseprojec

  10. ruby TFTP 服务器 - 2

    我将以下代码放在一起用于一个简单的RubyTFTP服务器。它工作正常,因为它监听端口69并且我的TFTP客户端连接到它,我能够将数据包写入test.txt,但我不只是写入数据包,我希望能够从我的客户端通过TFTP传输文件到/temp目录。预先感谢您的帮助!require'socket.so'classTFTPServerdefinitialize(port)@port=portenddefstart@socket=UDPSocket.new@socket.bind('',@port)whiletruepacket=@socket.recvfrom(1024)putspacketFile

随机推荐