Kubernetes(k8s) 資源限制:resources,LimitRange,ResourceQuota

2023-07-05 15:02:35

一.系統環境

本文主要基於Kubernetes1.21.9和Linux作業系統CentOS7.4。

伺服器版本 docker軟體版本 Kubernetes(k8s)叢集版本 CPU架構
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 x86_64

Kubernetes叢集架構:k8scloude1作為master節點,k8scloude2,k8scloude3作為worker節點。

伺服器 作業系統版本 CPU架構 程序 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master節點
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker節點

二.前言

在Kubernetes中,資源限制是一種管理和控制容器資源使用的重要機制。通過資源限制,我們可以為容器分配適當的計算資源,確保叢集的穩定性和效能。

本篇部落格將介紹Kubernetes中的資源限制的概念,並詳細說明如何使用resourcesLimitRangeResourceQuota來管理容器資源。

使用Kubernetes資源限制的前提是已經有一套可以正常執行的Kubernetes叢集,關於Kubernetes(k8s)叢集的安裝部署,可以檢視部落格《Centos7 安裝部署Kubernetes(k8s)叢集》https://www.cnblogs.com/renshengdezheli/p/16686769.html。

三.Kubernetes資源限制簡介

在Kubernetes中,資源限制是一種指定容器在節點上可使用的資源量的方法。資源主要包括計算資源(如CPU和記憶體),還可以包括其他擴充套件資源(如GPU、儲存等)。通過資源限制,我們可以控制容器對叢集資源的使用,並確保不同容器之間的資源分配合理,避免資源競爭和衝突。

四.建立沒有資源限制的pod

4.1 建立沒有資源限制的pod

在kubernetes叢集的所有節點下載centos映象。

[root@k8scloude1 ~]# cd safe/

[root@k8scloude1 safe]# docker pull hub.c.163.com/library/centos:latest

[root@k8scloude2 ~]# docker pull hub.c.163.com/library/centos:latest

[root@k8scloude3 ~]# docker pull hub.c.163.com/library/centos:latest

準備好memload安裝包,memload是記憶體消耗測試工具。

[root@k8scloude1 safe]# ls  memload-7.0-1.r29766.x86_64.rpm
memload-7.0-1.r29766.x86_64.rpm  

如下yaml檔案功能為:使用hub.c.163.com/library/centos:latest映象建立一個休眠10000000秒的pod。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

檢視pod,可以看到pod執行在k8scloude2節點上。

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          7s    10.244.112.180   k8scloude2   <none>           <none>

4.2 記憶體消耗測試

把memload安裝包拷貝到pod裡面。

[root@k8scloude1 safe]# kubectl cp memload-7.0-1.r29766.x86_64.rpm podtest:/opt

進入pod裡面。

[root@k8scloude1 safe]# kubectl exec -it podtest -- bash

#memload-7.0-1.r29766.x86_64.rpm安裝包已經在容器裡了
[root@podtest /]# ls /opt/
memload-7.0-1.r29766.x86_64.rpm

#安裝memload
[root@podtest /]# rpm -ivh /opt/memload-7.0-1.r29766.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:memload-7.0-1.r29766             ################################# [100%]
   
#在pod裡面執行memload 1024,使其消耗1024M的記憶體   
[root@podtest /]# memload 1024
Attempting to allocate 1024 Mebibytes of resident memory...
^C

因為podtest執行在k8scloude2節點上,所以在k8scloude2節點上觀察記憶體消耗情況,podtest裡沒執行memload 1024之前,k8scloude2節點記憶體消耗情況如下。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920         692         660          17        1567        1910
Swap:             0           0           0

在podtest裡執行memload 1024之後,k8scloude2節點記憶體消耗情況如下。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920        1718         101          17        1099         886
Swap:             0           0           0

podtest裡取消執行memload 1024之後,記憶體消耗降下來了。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920         688        1126          17        1105        1916
Swap:             0           0           0

在podtest裡繼續執行memload 1500,使其消耗1500M的記憶體。

[root@podtest /]# memload 1500
Attempting to allocate 1500 Mebibytes of resident memory...
^C

在k8scloude2節點上繼續觀察記憶體消耗。

首先清除一下快取。

[root@k8scloude2 ~]# echo 3 > /proc/sys/vm/drop_caches 

podtest裡沒執行memload 1500之前,k8scloude2節點記憶體消耗情況如下。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920         670        1770          17         479        1957
Swap:             0           0           0

在podtest裡執行memload 1500之後,k8scloude2節點記憶體消耗情況如下。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920        2178         134          17         607         448
Swap:             0           0           0

podtest裡取消執行memload 1500之後,記憶體消耗降下來了。

[root@k8scloude2 ~]# free -m
              total        used        free      shared  buff/cache   available
Mem:           2920         671        1640          17         608        1956
Swap:             0           0           0

刪除pod。

[root@k8scloude1 safe]# kubectl get pod 
NAME      READY   STATUS    RESTARTS   AGE
podtest   1/1     Running   0          26m

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

[root@k8scloude1 safe]# kubectl get pod 
No resources found in safe namespace.

由此我們可以發現:現在沒有對pod進行資源限制,pod可以無限制的使用記憶體,CPU等等,接下來對pod進行資源限制。

五.使用resources欄位設定資源限制

在Kubernetes中,resources欄位是一種用於定義和管理容器資源需求和限制的物件。通過指定資源請求和限制,Kubernetes可以根據叢集的可用資源進行排程和管理。

資源包括計算資源(如CPU和記憶體)以及其他可選的擴充套件資源(如GPU、儲存等)。通過合理設定資源,我們可以避免容器之間的資源競爭和衝突,提高應用程式的效能和可靠性。

5.1 限制最低記憶體

修改yaml檔案,對pod的資源限制可以通過pod裡的resource欄位來限制,resources裡的requests欄位表示容器所在節點資源的最小值,最低要求,滿足不了這個要求pod建立不成功。

requests:memory: 100Gi表示podtest最低要求100Gi記憶體,滿足不了,pod就建立失敗。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: 
      #requests:memory: 100Gi表示podtest最低要求100Gi記憶體,滿足不了pod就建立失敗。
      requests:
        memory: 100Gi
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

檢視pod,我們現在的機器環境滿足不了100G的記憶體要求,所以pod狀態為Pending。

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
podtest   0/1     Pending   0          9s    <none>   <none>   <none>           <none>

刪除pod。

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

5.2 限制最低CPU

修改yaml檔案,requests:cpu: 4 表示podtest最低要求有4核CPU,滿足不了,pod就建立失敗。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: 
      #requests:cpu: 4 表示podtest最低要求有4核CPU,滿足不了,pod就建立失敗
      requests:
        cpu: 4
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

檢視pod,4核CPU無法滿足,pod狀態為Pending。

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
podtest   0/1     Pending   0          13s   <none>   <none>   <none>           <none>

刪除pod。

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

修改yaml檔案,requests:cpu: 3 表示podtest最低要求有3核CPU,滿足不了,pod就建立失敗。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 10000000"]
    resources: 
      #requests:cpu: 3 表示podtest最低要求有3核CPU,滿足不了,pod就建立失敗
      requests:
        cpu: 3
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

requests:cpu: 3 要求有3核CPU之後,podtest滿足條件,pod就執行起來了。requests:cpu: 3 可以換成requests:cpu: 3000m ,兩者是等價的,1核等於1000個微核心。

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          4s    10.244.112.170   k8scloude2   <none>           <none>

檢視節點負載。

[root@k8scloude1 safe]# kubectl top node 
W0323 08:56:05.755124   39033 top_node.go:119] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
k8scloude1   311m         7%     1429Mi          50%       
k8scloude2   172m         4%     839Mi           29%       
k8scloude3   188m         4%     959Mi           34%  

檢視safe名稱空間的pod負載。

[root@k8scloude1 safe]# kubectl top pod -n safe
W0323 08:56:47.844614   39714 top_pod.go:140] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
NAME      CPU(cores)   MEMORY(bytes)   
podtest   0m           2Mi            

刪除pod。

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

[root@k8scloude1 safe]# kubectl get pod
No resources found in safe namespace.

5.3 限制最低CPU和最高記憶體

修改yaml檔案,resources:limits表示容器消耗資源最大值,limits: memory: 500Mi 表示容器最多消耗500M記憶體,requests:cpu: 300m 表示podtest最低要求有300個微核心,滿足不了,pod就建立失敗。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: 
      #requests:cpu: 300m 表示podtest最低要求有300個微核心,滿足不了,pod就建立失敗
      requests:
        cpu: 300m
      #limits: memory: 500Mi 表示容器最多消耗500M記憶體  
      limits:
        memory: 500Mi
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

檢視pod,pod建立成功。

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          7s    10.244.112.188   k8scloude2   <none>           <none>

5.4 記憶體消耗測試

再次進行資源消耗測試,把memload-7.0-1.r29766.x86_64.rpm安裝包拷貝到podtest裡。

[root@k8scloude1 safe]# kubectl cp memload-7.0-1.r29766.x86_64.rpm podtest:/opt

進入pod。

[root@k8scloude1 safe]# kubectl exec -it podtest -- bash

#安裝memload
[root@podtest /]# rpm -ivh /opt/memload-7.0-1.r29766.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:memload-7.0-1.r29766             ################################# [100%]
   
#memload 1024消耗1024M記憶體就自動 killed了 
[root@podtest /]# memload 1024
Attempting to allocate 1024 Mebibytes of resident memory...
Killed   

#memload 600消耗600M記憶體就自動 killed了 
[root@podtest /]# memload 600 
Attempting to allocate 600 Mebibytes of resident memory...
Killed

#memload 490消耗490M記憶體就可以
[root@podtest /]# memload 490
Attempting to allocate 490 Mebibytes of resident memory...
^C

#退出pod
[root@podtest /]# exit
exit
command terminated with exit code 130

可以發現記憶體消耗不能大於limits:memory: 500Mi,大於500M的記憶體設定就會OOM Killed,資源限制成功。

刪除pod。

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

[root@k8scloude1 safe]# kubectl get pod 
No resources found in safe namespace.

六.使用LimitRange限制資源範圍

LimitRange是一種用於限制容器資源使用的設定物件。它允許叢集管理員定義資源的最小和最大限制,並確保容器在這些限制範圍內使用資源。

通過使用LimitRange,可以避免容器使用過多或過少的資源,保護叢集免受資源耗盡和應用程式崩潰的影響。

預設情況下, Kubernetes 叢集上的容器執行使用的計算資源沒有限制。 使用 Kubernetes 資源配額, 管理員(也稱為 叢集操作者)可以在一個指定的名稱空間內限制叢集資源的使用與建立。 在名稱空間中,一個 Pod 最多能夠使用名稱空間的資源配額所定義的 CPU 和記憶體用量。 作為叢集操作者或名稱空間級的管理員,你可能也會擔心如何確保一個 Pod 不會壟斷名稱空間內所有可用的資源。

LimitRange 是限制名稱空間內可為每個適用的物件類別 (例如 Pod 或 PersistentVolumeClaim) 指定的資源分配量(限制和請求)的策略物件。

一個 LimitRange(限制範圍) 物件提供的限制能夠做到:

  • 在一個名稱空間中實施對每個 Pod 或 Container 最小和最大的資源使用量的限制。

  • 在一個名稱空間中實施對每個 PersistentVolumeClaim 能申請的最小和最大的儲存空間大小的限制。

  • 在一個名稱空間中實施對一種資源的申請值和限制值的比值的控制。

  • 設定一個名稱空間中對計算資源的預設申請/限制值,並且自動的在執行時注入到多個 Container 中。

當某名稱空間中有一個 LimitRange 物件時,將在該名稱空間中實施 LimitRange 限制。

如下LimitRange的功能為:建立了一個名為"mem-limit-range"的LimitRange資源物件,用於限制容器的記憶體使用範圍。容器的記憶體限制在256Mi到512Mi之間,並且僅適用於容器。

[root@k8scloude1 safe]# vim limitRange.yaml

[root@k8scloude1 safe]# cat limitRange.yaml 
apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  #memory: 512Mi:設定容器的最大記憶體限制為512MiB。
  - max:
      memory: 512Mi
    #memory: 256Mi:設定容器的最小記憶體限制為256MiB。  
    min:
      memory: 256Mi
    #type: Container:指定這些限制適用於容器。  
    type: Container

建立LimitRange。

[root@k8scloude1 safe]# kubectl apply -f limitRange.yaml 
limitrange/mem-limit-range created

檢視LimitRange。

[root@k8scloude1 safe]# kubectl get LimitRange
NAME              CREATED AT
mem-limit-range   2022-03-23T01:23:04Z

[root@k8scloude1 safe]# kubectl get -f limitRange.yaml 
NAME              CREATED AT
mem-limit-range   2022-03-23T01:23:04Z

檢視mem-limit-range的描述資訊。

[root@k8scloude1 safe]# kubectl describe LimitRange mem-limit-range
Name:       mem-limit-range
Namespace:  safe
Type        Resource  Min    Max    Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---    ---------------  -------------  -----------------------
Container   memory    256Mi  512Mi  512Mi            512Mi          -

[root@k8scloude1 safe]# kubectl describe -f limitRange.yaml 
Name:       mem-limit-range
Namespace:  safe
Type        Resource  Min    Max    Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---    ---------------  -------------  -----------------------
Container   memory    256Mi  512Mi  512Mi            512Mi          -

使用hub.c.163.com/library/centos:latest映象建立pod。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: {} 
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          7s    10.244.112.189   k8scloude2   <none>           <none>

把memload安裝包拷貝到podtest裡。

[root@k8scloude1 safe]# kubectl cp memload-7.0-1.r29766.x86_64.rpm podtest:/opt

進入pod,進行記憶體消耗測試。

[root@k8scloude1 safe]# kubectl exec -it podtest -- bash

#安裝memload
[root@podtest /]# rpm -ivh /opt/memload-7.0-1.r29766.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:memload-7.0-1.r29766             ################################# [100%]

#memload 1024表示消耗1024M記憶體,1024M記憶體超過limits:max:memory: 512Mi,直接就Killed
[root@podtest /]# memload 1024
Attempting to allocate 1024 Mebibytes of resident memory...
Killed

#memload 500 表示消耗500M記憶體,500M小於limits:max:memory: 512Mi,成功消耗記憶體
[root@podtest /]# memload 500 
Attempting to allocate 500 Mebibytes of resident memory...
^C

[root@podtest /]# exit
exit
command terminated with exit code 130

可以發現容器記憶體設定不能超過limits:max:memory: 512Mi,成功進行資源限制。

刪除pod。

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

七.同時使用LimitRange和resource欄位設定資源限制

修改yaml檔案,resources欄位和LimitRange都進行了資源限制,requests:memory: 200Mi表示podtest最低要求200Mi記憶體,滿足不了pod就建立失敗,limits: memory: 600Mi 表示容器最多消耗600Mi記憶體 。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 10000000"]
    resources:
      #requests:memory: 200Mi表示podtest最低要求200Mi記憶體,滿足不了pod就建立失敗。
      requests:
        memory: 200Mi 
      #limits: memory: 600Mi 表示容器最多消耗600Mi記憶體    
      limits:
        memory: 600Mi 
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

LimitRange的限制範圍為256Mi到512Mi記憶體。

[root@k8scloude1 safe]# kubectl get LimitRange
NAME              CREATED AT
mem-limit-range   2022-03-23T01:23:04Z

[root@k8scloude1 safe]# kubectl describe -f limitRange.yaml 
Name:       mem-limit-range
Namespace:  safe
Type        Resource  Min    Max    Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---    ---------------  -------------  -----------------------
Container   memory    256Mi  512Mi  512Mi            512Mi          -

建立pod,pod建立失敗,只有滿足LimitRange min <= requests <limits <= LimitRange max 條件,pod才能建立成功,resources欄位指定的記憶體範圍應該是LimitRange的真子集。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
Error from server (Forbidden): error when creating "pod.yaml": pods "podtest" is forbidden: [minimum memory usage per Container is 256Mi, but request is 200Mi, maximum memory usage per Container is 512Mi, but limit is 600Mi]

修改yaml檔案,requests:memory: 300Mi表示podtest最低要求300Mi記憶體,滿足不了pod就建立失敗,limits: memory: 500Mi 表示容器最多消耗500M記憶體 。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 10000000"]
    resources:
      #requests:memory: 300Mi表示podtest最低要求300Mi記憶體,滿足不了pod就建立失敗。
      requests:
        memory: 300Mi 
      #limits: memory: 500Mi 表示容器最多消耗500M記憶體    
      limits:
        memory: 500Mi 
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

LimitRange的限制範圍為256Mi到512Mi記憶體。

[root@k8scloude1 safe]# kubectl describe -f limitRange.yaml 
Name:       mem-limit-range
Namespace:  safe
Type        Resource  Min    Max    Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---    ---------------  -------------  -----------------------
Container   memory    256Mi  512Mi  512Mi            512Mi          -

建立pod,pod建立成功,因為滿足LimitRange min <= requests <limits <= LimitRange max 條件。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

[root@k8scloude1 safe]# kubectl get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
podtest   1/1     Running   0          7s    10.244.112.190   k8scloude2   <none>           <none>

如果resources欄位和LimitRange都進行了資源限制,最終是resources欄位生效,容器記憶體設定不能大於500Mi。

刪除limitrange和pod。

[root@k8scloude1 safe]# kubectl delete -f limitRange.yaml 
limitrange "mem-limit-range" deleted

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

八.使用ResourceQuota資源配額管理

ResourceQuota是一種用於限制名稱空間內資源使用的物件。它允許叢集管理員對名稱空間中的資源使用進行配額管理,確保不同的團隊或專案之間資源的公平分配和有效利用。

使用ResourceQuota,可以限制名稱空間中的CPU、記憶體和其他資源的總量,防止資源濫用和浪費。

資源配額,通過 ResourceQuota 物件來定義,對每個名稱空間的資源消耗總量提供限制。 它可以限制名稱空間中某種型別的物件的總數目上限,也可以限制名稱空間中的 Pod 可以使用的計算資源的總上限。

資源配額的工作方式如下:

  • 不同的團隊可以在不同的名稱空間下工作。這可以通過 RBAC 強制執行。

  • 叢集管理員可以為每個名稱空間建立一個或多個 ResourceQuota 物件。

  • 當用戶在名稱空間下建立資源(如 Pod、Service 等)時,Kubernetes 的配額系統會跟蹤叢集的資源使用情況, 以確保使用的資源用量不超過 ResourceQuota 中定義的硬性資源限額。

  • 如果資源建立或者更新請求違反了配額約束,那麼該請求會報錯(HTTP 403 FORBIDDEN), 並在訊息中給出有可能違反的約束。

  • 如果名稱空間下的計算資源 (如 cpu 和 memory)的配額被啟用, 則使用者必須為這些資源設定請求值(request)和約束值(limit),否則配額系統將拒絕 Pod 的建立。 提示: 可使用 LimitRanger 准入控制器來為沒有設定計算資源需求的 Pod 設定預設值。

簡而言之,resourcequota 配額就是用來設定一個名稱空間最多能建立多少個物件,比如能建立多少svc,能建立多少pod/deploy。

如下yaml檔案功能為:使用hub.c.163.com/library/centos:latest映象建立一個休眠10000000秒的pod。

[root@k8scloude1 safe]# vim pod.yaml 

[root@k8scloude1 safe]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: podtest
  name: podtest
spec:
  #當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
  terminationGracePeriodSeconds: 0
  containers:
  - name: centos
    image: hub.c.163.com/library/centos:latest
    #imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
    imagePullPolicy: IfNotPresent
    #command: ["sh","-c","sleep 10000000"]指定容器啟動時要執行的命令,這裡是在容器內部執行一個sleep命令,休眠時間為10000000秒。
    command: ["sh","-c","sleep 10000000"]
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

建立pod。

[root@k8scloude1 safe]# kubectl apply -f pod.yaml 
pod/podtest created

[root@k8scloude1 safe]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
podtest   1/1     Running   0          3s

給podtest建立4個svc,關於svc的詳細內容,請檢視部落格《Kubernetes(k8s)服務service:service的發現和service的釋出》。

[root@k8scloude1 safe]# kubectl expose --name=svc1 pod podtest --port=80
service/svc1 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc2 pod podtest --port=80
service/svc2 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc3 pod podtest --port=80
service/svc3 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc4 pod podtest --port=80
service/svc4 exposed

可以發現,此時可以建立很多個svc。

[root@k8scloude1 safe]# kubectl get svc -o wide
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc1   ClusterIP   10.98.89.245     <none>        80/TCP    21s   test=podtest
svc2   ClusterIP   10.109.215.162   <none>        80/TCP    15s   test=podtest
svc3   ClusterIP   10.96.10.12      <none>        80/TCP    12s   test=podtest
svc4   ClusterIP   10.109.113.59    <none>        80/TCP    7s    test=podtest

刪除svc。

[root@k8scloude1 safe]# kubectl delete svc svc1 svc2 svc3 svc4
service "svc1" deleted
service "svc2" deleted
service "svc3" deleted
service "svc4" deleted

[root@k8scloude1 safe]# kubectl get svc -o wide
No resources found in safe namespace.

現在還沒有資源配額resourcequotas。

[root@k8scloude1 safe]# kubectl get resourcequotas 
No resources found in safe namespace.

設定ResourceQuota,功能為建立了一個名為"resourcequota"的ResourceQuota資源物件,用於限制叢集中的資源配額。使用該ResourceQuota,最多隻能建立4個Pod和4個Service。當達到或超過這些限制時,將無法再建立新的Pod或Service,從而避免過度消耗資源並提高整個叢集的可靠性和穩定性。

[root@k8scloude1 safe]# vim resourcequotas.yaml 

#只能建立4個pod和4個svc
[root@k8scloude1 safe]# cat resourcequotas.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:
  name: resourcequota
spec:
  #hard:指定資源的硬性限制,即最大允許使用的資源數量。
  hard:
    #pods: "4":設定該叢集中最多可以建立4個Pod。
    pods: "4"
    #services: "4":設定該叢集中最多可以建立4個Service。
    services: "4"

建立ResourceQuota。

[root@k8scloude1 safe]# kubectl apply -f resourcequotas.yaml 
resourcequota/resourcequota created

檢視ResourceQuota。

[root@k8scloude1 safe]# kubectl get resourcequotas 
NAME            AGE   REQUEST                    LIMIT
resourcequota   6s    pods: 1/4, services: 0/4   

現在有1個pod,0個service。

[root@k8scloude1 safe]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
podtest   1/1     Running   0          10m

[root@k8scloude1 safe]# kubectl get svc
No resources found in safe namespace.

檢視resourcequota的描述資訊。

[root@k8scloude1 safe]# kubectl describe -f resourcequotas.yaml 
Name:       resourcequota
Namespace:  safe
Resource    Used  Hard
--------    ----  ----
pods        1     4
services    0     4

建立svc。

[root@k8scloude1 safe]# kubectl expose --name=svc1 pod podtest --port=80
service/svc1 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc2 pod podtest --port=80
service/svc2 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc3 pod podtest --port=80
service/svc3 exposed

[root@k8scloude1 safe]# kubectl expose --name=svc4 pod podtest --port=80
service/svc4 exposed

[root@k8scloude1 safe]# kubectl get svc
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
svc1   ClusterIP   10.110.233.61    <none>        80/TCP    37s
svc2   ClusterIP   10.105.108.94    <none>        80/TCP    34s
svc3   ClusterIP   10.105.226.140   <none>        80/TCP    29s
svc4   ClusterIP   10.98.10.38      <none>        80/TCP    25s

svc只能建立4個,第五個就建立失敗了。

[root@k8scloude1 safe]# kubectl expose --name=svc5 pod podtest --port=80
Error from server (Forbidden): services "svc5" is forbidden: exceeded quota: resourcequota, requested: services=1, used: services=4, limited: services=4

檢視resourcequotas,可以看到service配額已經滿了。

[root@k8scloude1 safe]# kubectl get resourcequotas 
NAME            AGE     REQUEST                    LIMIT
resourcequota   2m17s   pods: 1/4, services: 4/4   

刪除svc,pod,resourcequotas。

[root@k8scloude1 safe]# kubectl delete svc svc1 svc2
service "svc1" deleted
service "svc2" deleted

[root@k8scloude1 safe]# kubectl delete svc svc3 svc4
service "svc3" deleted
service "svc4" deleted

[root@k8scloude1 safe]# kubectl delete pod podtest 
pod "podtest" deleted

[root@k8scloude1 safe]# kubectl delete -f resourcequotas.yaml 
resourcequota "resourcequota" deleted

九.總結

本篇部落格介紹了Kubernetes中資源限制的概念以及如何使用resourcesLimitRangeResourceQuota來管理容器資源。通過合理設定資源限制,可以提高叢集的穩定性和效能,並確保資源的公平分配和有效利用。

資源限制是Kubernetes中重要的管理和控制機制,對於構建可靠且高效的應用程式環境至關重要。