從 Request/Limit 走到 LimitRange#

前面兩章已經介紹了 Request 與 Limit,以及作為資源分組單位的 Namespace。把兩者結合起來,自然會出現一個新的需求:「能不能在 Namespace 層級替每個容器設一組合理的預設值,並且擋掉不合理的設定?」

預設情況下,Kubernetes 對容器內的資源使用是不設限的。如果 Pod 沒有自己宣告 Request 與 Limit,就有機會直接吃掉整個節點的資源。LimitRange 就是 Namespace 層級用來規範這件事的政策物件(Policy Object)。

LimitRange 能做什麼#

LimitRange 依附在某個 Namespace 之下,可以同時提供以下幾種能力:

  • 對 Namespace 中的每個 Pod 或 Container 設定資源使用的上下限。
  • 對每個 PersistentVolumeClaim 可申請的儲存空間設定上下限。
  • 控制同一種資源的 Request 與 Limit 比值。
  • 替沒有自行宣告資源的容器,注入預設的 Request 與 Limit。

動手實作#

建立 Namespace#

kubectl create ns demo-namespace

把這個 Namespace 設為當前 context 的預設值:

kubectl config set-context --current --namespace=demo-namespace

建立提供預設值的 LimitRange#

# limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: limit-range
spec:
  limits:
    - default:
        cpu: 1000m
        memory: 500Mi
      defaultRequest:
        cpu: 500m
        memory: 200Mi
      type: Container

查看建立好的 LimitRange:

kubectl get limitrange limit-range --output=yaml

擷取重點輸出:

limits:
  - default:
      cpu: "1"
      memory: 500Mi
    defaultRequest:
      cpu: 500m
      memory: 200Mi
    type: Container

LimitRange 建好之後,這個 Namespace 內接下來的容器有兩種情況:

  • 容器沒有自己宣告 Request 與 Limit:Kubernetes 會用 LimitRange 中的 defaultRequestdefault 自動補上。
  • 容器有宣告 Request 或 Limit:必須落在 LimitRange 的範圍內,否則會被擋下來。

換成清楚的條件:

  • Pod 內任一容器若沒有宣告 Request/Limit,會被自動帶入 LimitRange 的預設值。
  • 每個容器宣告的 Request 至少要 >= limits.defaultRequest
  • 每個容器宣告的 Limit 至少要 <= limits.default

建立一個沒有宣告資源的 Pod#

# limit-range-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: limit-range-pod
spec:
  containers:
    - name: default-limit-range-pod
      image: nginx

部署:

kubectl apply -f ./limit-range-pod.yaml

查看 Pod 的 spec,確認 LimitRange 真的有把預設值塞進來:

kubectl get pod limit-range-pod --output=yaml

預期會看到:

containers:
  - image: nginx
    imagePullPolicy: Always
    name: limit-range-pod
    resources:
      limits:
        cpu: "1"
        memory: 500Mi
      requests:
        cpu: 500m
        memory: 200Mi

嘗試建立超出範圍的 Pod#

當 Pod 宣告的 CPU Limit 超過 LimitRange 的最大值時,Kubernetes 會直接拒絕:

Error from server (Forbidden): error when creating "examples/admin/resource/limit-range-pod.yaml":
pods "limit-range-pod" is forbidden: maximum cpu usage per Container is 800m, but limit is 1500m.

反過來,當宣告的 CPU Request 低於 LimitRange 規範的最小值時,也會被擋:

Error from server (Forbidden): error when creating "examples/admin/resource/limit-range-pod.yaml":
pods "limit-range-pod" is forbidden: minimum cpu usage per Container is 200m, but request is 100m.

小結#

Namespace 把資源切成不同分組,LimitRange 在分組內提供了「預設值 + 上下限」的雙重保護。實務上常會再搭配 ResourceQuota,從 Namespace 整體可用資源、可建立物件數量等角度做進一步的把關,讓不同部門能在同一個叢集中安心共用資源。

原文出處#

  • GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day23
  • iThome:https://ithelp.ithome.com.tw/articles/10296817