如何設定Kubernetes資源限制

蕭元發表於2018-07-10

Kubernetes 作為當下最流行的的容器叢集管理平臺,需要統籌叢集整體的資源使用情況,將合適的資源分配給pod容器使用,既要保證充分利用資源,提高資源利用率,又要保證重要容器在執行週期內能夠分配到足夠的資源穩定執行。

配置容器資源限制

對於一個pod來說,資源最基礎的2個的指標就是:CPU和記憶體。
Kubernetes提供了個採用requests和limits 兩種型別引數對資源進行預分配和使用限制。
limit 會限制pod的資源利用:

  • 當pod 記憶體超過limit時,會被oom。
  • 當cpu超過limit時,不會被kill,但是會限制不超過limit值。

測試記憶體限制

部署一個壓測容器,壓測時會分配250M記憶體,但實際pod的記憶體limit為100Mi

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

部署後檢視pod狀態,可以看到pod被OOM,

  kubectl -n example get po
NAME             READY     STATUS        RESTARTS   AGE
memory-demo      0/1       OOMKilled     1          11s

測試CPU限制

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
  namespace: example
spec:
  containers:
  - name: cpu-demo-ctr
    image: vish/stress
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: "0.5"
    args:
    - -cpus
    - "2"

檢視容器資訊,可以看到pod 雖然不會被kill掉,但是實際使用cpu被限制只有1000m。

 kubectl -n example top po cpu-demo
NAME       CPU(cores)   MEMORY(bytes)
cpu-demo   1000m        0Mi

容器服務質量(QoS)

Kubernetes 提供服務質量管理,根據容器的資源配置,將pod 分為Guaranteed, Burstable, BestEffort 3個級別。當資源緊張時根據分級決定排程和驅逐策略,這三個分級分別代表:

  • Guaranteed: pod中所有容器都設定了limit和request, 並且相等(設定limit後假如沒有設定request會自動設定為limit值)
  • Burstable: pod中有容器未設定limit, 或者limit和request不相等。這種型別的pod在排程節點時, 可能出現節點超頻的情況。
  • BestEffort: pod中沒有任何容器設定request和limit。

計算qos程式碼:https://github.com/kubernetes/kubernetes/blob/master/pkg/apis/core/helper/qos/qos.go

不同QoS對容器影響

oom:

Kubernetes會根據QoS設定oom的評分調整引數oom_score_adj,oom_killer 根據 記憶體使用情況算出oom_score, 並且和oom_score_adj綜合評價,程式的評分越高,當發生oom時越優先被kill。

QoS oom_score_adj
Guaranteed -998
BestEffort 1000
Burstable min(max(2, 1000 – (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)

當節點記憶體不足時,QoS為Guaranteed 的pod 最後被kill。 而BestEffort 級別的pod優先被kill。 其次是Burstable,根據計算公式 oom_score_adj 值範圍2到999,設定的request越大,oom_score_adj越低,oom時保護程度越高。

實踐
節點資訊:
# kubectl describe no cn-beijing.i-2zeavb11mttnqnnicwj9 | grep -A 3 Capacity
Capacity:
 cpu:     4
 memory:  8010196Ki
 pods:    110
apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-qos-1
  namespace: example
spec:
  containers:
  - name: memory-demo-qos-1
    image: polinux/stress
    resources:
      requests:
        memory: "200Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "50M", "--vm-hang", "1"]
    
---
apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-qos-2
  namespace: example
spec:
  containers:
  - name: memory-demo-qos-2
    image: polinux/stress
    resources:
      requests:
        memory: "400Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "50M", "--vm-hang", "1"]

---
apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-qos-3
  namespace: example
spec:
  containers:
  - name: memory-demo-qos-3
    image: polinux/stress
    resources:
      requests:
        memory: "200Mi"
        cpu: "2"
      limits:
        memory: "200Mi"
        cpu: "2"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "50M", "--vm-hang", "1"]

單個節點可分配記憶體為8010196Ki, 大約7822.45Mi。
根據Burstable 的計算方式:


request 200Mi: (1000 - 1000*200/7822.45) 約為975

request 400Mi: (1000 - 1000*400/7822.45) 約為950

我們分別檢視這3個pod的oom引數

// request 200Mi
  kubectl -n example exec  memory-demo-qos-1 cat /proc/1/oom_score_adj
975

// request 400Miß
  kubectl -n example exec  memory-demo-qos-2 cat /proc/1/oom_score_adj
949

// Guaranteed
  kubectl -n example exec  memory-demo-qos-3 cat /proc/1/oom_score_adj
-998

設定oom 規則程式碼: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/qos/policy.go

pod 驅逐:

當節點的記憶體和cpu資源不足,開始驅逐節點上的pod時。QoS同樣會影響驅逐的優先順序。順序如下:

  1. kubelet 優先驅逐 BestEffort的pod 和 實際佔用資源大於requests的Burstable pod。
  • 接下來驅逐實際佔用資源小於request的Burstable pod。
  • QoS為Guaranteed的pod最後驅逐, kubelet 會保證Guaranteed的pod 不會因為其他pod的資源消耗而被驅逐。
  • 當QoS相同時,kubelet 根據 Priority 計算驅逐的優先順序

ResourceQuota

Kubernetes提供ResourceQuota物件,用於配置限制namespace內的每種型別的k8s物件數量和資源(cpu,記憶體)。

  • 一個namespace中可以建立一個或多個ResourceQuota
  • 如果namespace中配置了ResourceQuota, 部署時必須設定request和limit, 否則會拒絕建立請求。
  • 可以通過這是limitRange配置每個pod預設的requests和limits避免上述問題
  • 1.10以後支援擴充套件資源 詳見:https://kubernetes.io/docs/tasks/configure-pod-container/extended-resource/
apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-demo
  namespace: example
spec:
  hard:
    requests.cpu: "3"
    requests.memory: 1Gi
    limits.cpu: "5"
    limits.memory: 2Gi
    pods: "5"

LimitRange

LimitRange 是用來設定 namespace 中 Pod 的預設的資源 request 和 limit 值,以及大小範圍。

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
  namespace: example
spec:
  limits:
  - default:  # default limit
      memory: 512Mi
      cpu: 2
    defaultRequest:  # default request
      memory: 256Mi
      cpu: 0.5
    max:  # max limit
      memory: 800Mi
      cpu: 3
    min:  # min request
      memory: 100Mi
      cpu: 0.3
    maxLimitRequestRatio:  # max value for limit / request
      memory: 2
      cpu: 2
    type: Container # limit type, support: Container / Pod / PersistentVolumeClaim

limitRange支援的引數如下:

  • default 代表預設的limit
  • defaultRequest 代表預設的request
  • max 代表limit的最大值
  • min 代表request的最小值
  • maxLimitRequestRatio 代表 limit / request的最大值。由於節點是根據pod request 排程資源,可以做到節點超賣,maxLimitRequestRatio 代表pod最大超賣比例。

總結

  • Kubernetes 提供request 和 limit 兩種方式設定容器資源。
  • 為了提高資源利用率,k8s排程時根據pod 的request值計算排程策略,從而實現節點資源超賣。
  • k8s根據limit限制pod使用資源,當記憶體超過limit時會觸發oom。 且限制pod的cpu 不允許超過limit。
  • 根據pod的 request和limit,k8s會為pod 計算服務質量,並分為Guaranteed, Burstable, BestEffort 這3級。當節點資源不足時,發生驅逐或者oom時, Guaranteed 級別的pod 優先保護, Burstable 節點次之(request越大,使用資源量越少 保護級別越高), BestEffort 最先被驅逐。
  • Kubernetes提供了RequestQuota和LimitRange 用於設定namespace 內pod 的資源範圍 和 規模總量。 RequestQuota 用於設定各種型別物件的數量, cpu和記憶體的總量。 LimitRange 用於設定pod或者容器 request和limit 的預設值,最大最小值, 以及超賣比例(limit / request)。
  • 對於一些重要的線上應用,我們應該合理設定limit和request,limit和request 設定一致,資源不足時k8s會優先保證這些pod正常執行。
  • 為了提高資源利用率。 對一些非核心,並且資源不長期佔用的應用,可以適當減少pod的request,這樣pod在排程時可以被分配到資源不是十分充裕的節點,提高使用率。但是當節點的資源不足時,也會優先被驅逐或被oom kill。

參考文件


相關文章