K8S實戰(十八)| 容器資源分配和資源限制


前言

為了防止容器調度到資源不足的節點上,可以為容器指定資源最少要求量。

為了防止容器無節制的使用 CPU、內存 等資源,可以為容器指定資源最大允許使用量。

更新歷史

資源請求和資源約束

可以為容器指定資源請求量和資源約束量。

資源一般指 CPU、內存。

資源請求量,指容器要求節點分配的最小容量,如果該節點可用容量小於容器要求的請求量,容器將被調度到其他合適節點。

資源約束量,指容器要求節點限制其使用的最大容量,如果容器內存使用量超過內容約束量,容器將被殺掉,如果指定了重啟策略,容器殺掉后將被重啟。

涉及的參數

約束量
spec.containers[].resources.limits.cpu
spec.containers[].resources.limits.memory
spec.containers[].resources.limits.hugepages-<size>

請求量
spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.requests.hugepages-<size>

示例

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

資源單位

K8S 中的一個 cpu 等於雲平台上的 1 個 vCPU/核或裸機 Intel 處理器上的 1 個超線程

spec.containers[].resources.requests.cpu 為 0.5 的容器肯定能夠獲得請求 1 CPU 的容器的一半 CPU 資源。表達式 0.1 等價於表達式 100m, 可以看作 “100 millicpu”。具有小數點(如 0.1)的請求由 API 轉換為 100m;最大精度是 1m。

優先考慮使用 100m 的形式。

內存可以使用E、P、T、G、M、K。也可以使用對應的 2 的冪數:Ei、Pi、Ti、Gi、Mi、Ki。

Pod 的資源請求和約束

Pod 的請求量等於內部所有容器的請求量之和。

Pod 的約束量等於內部所有容器的約束量之和。

帶資源請求的 Pod 如何調度

調度程序確保所調度的 Pod 的資源請求量小於節點的容量。

即,調度程序將查找到資源可用量充足的,可用量大於請求量的節點來放置 Pod。

帶資源約束的 Pod 如何運行

內存資源約束

如果容器超過其內存最大限制,則可能會被終止。如果容器可重新啟動,kubelet 將重新啟動容器。

如果一個容器內存使用量超過其內存請求值,那么當節點內存不足時,容器所處的 Pod 可能被逐出。

CPU 資源約束

每個容器可能被允許也可能不被允許使用超過其 CPU 約束的處理時間。 但是,容器不會由於 CPU 使用率過高而被殺死。

spec.containers[].resources.limits.cpu 先被轉換為 millicore 值,再乘以 100。其結果就是每 100 毫秒內容器可以使用的 CPU 時間總量。在此期間(100ms),容器所使用的 CPU 時間不會超過它被分配的時間。

默認的配額(quota)周期為 100 毫秒。 CPU配額的最小精度為 1 毫秒。

如何獲知集群資源使用情況,需要通過 metrics-server 來獲取。

metrics-server

查看是否已安裝 metrics-server,以下說明沒安裝

# kubectl top node
Error from server (NotFound): the server could not find the requested resource (get services http:heapster:)
# kubectl get pods,svc,deployments -n kube-system | grep metrics-server
# 

開始安裝 metrics-server

git clone https://github.com/kubernetes-incubator/metrics-server
cd metrics-server/
git checkout release-0.3

修改 metrics-server/deploy/1.8+/metrics-server-deployment.yaml

      containers:
      - name: metrics-server
        #image: k8s.gcr.io/metrics-server/metrics-server:v0.3.6
        image: registry.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
        imagePullPolicy: IfNotPresent
        args:
          - --cert-dir=/tmp
          - --secure-port=4443
          - --metric-resolution=30s
          - --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
          - --kubelet-insecure-tls

參數說明

--metric-resolution=30s:從 kubelet 采集數據的周期;
--kubelet-preferred-address-types:優先使用 InternalIP 來訪問 kubelet,這樣可以避免節點名稱沒有 DNS 解析記錄時,通過節點名稱調用節點 kubelet API 失敗的情況(未配置時默認的情況);
--kubelet-insecure-tls:kubelet 的10250端口使用的是https協議,連接需要驗證tls證書。--kubelet-insecure-tls不驗證客戶端證書

安裝

kubectl apply -f deploy/1.8+/

再次查看,需要多等一會兒,確保采集到數據。

[root@master01 ~]# kubectl get --raw "/apis/metrics.k8s.io/v1beta1/nodes"
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[]}

[root@master01 1.8+]# kubectl top nodes
NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master01   163m         4%     2093Mi          56%       
master02   147m         3%     1638Mi          44%       
master03   151m         3%     1609Mi          43%       
work01     141m         3%     1084Mi          29%       
work02     150m         3%     1097Mi          29%       
work03     138m         3%     1471Mi          39%   

[root@master01 1.8+]# kubectl top pod
NAME                                      CPU(cores)   MEMORY(bytes)   
mysql-0                                   15m          202Mi           
mysql-1                                   14m          191Mi           
mysql-2                                   13m          182Mi           
nfs-client-provisioner-7db698bbc9-8ph55   2m           8Mi  

已經可以看到資源使用情況。

實踐內存限額

創建一個測試用命名空間

# kubectl create namespace mem-example
namespace/mem-example created

創建一個最大限額 100M,但最少需要 250M 的容器

# cat memory-request-limit-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-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"]
# kubectl apply -f memory-request-limit-2.yaml
pod/memory-demo-2 created

查看發現創建失敗

# kubectl get pod -n mem-example
NAME            READY   STATUS             RESTARTS   AGE
memory-demo-2   0/1     CrashLoopBackOff   3          88s

查看原因

# kubectl get pod -n mem-example -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' memory-demo-2
Container Name: memory-demo-2-ctr
LastState: map[terminated:map[containerID:docker://aaf41e exitCode:1 reason:OOMKilled ]]

其中有 reason:OOMKilled,說明超過了內存最大限額,導致了 OOM 然后被殺掉。

結束語

通過 resources.requests 和 resources.limits,可以對資源進行最少容量要求和最大容量限制,確保容器可以運行在資源充足的節點上,同時也不會由於自身占用了過多資源而影響節點上其他容器。

聯系我

微信公眾號:zuolinux_com

微信掃碼關注


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM