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

前言

爲了防止容器調度到資源不足的節點上,能夠爲容器指定資源最少要求量。html

爲了防止容器無節制的使用 CPU、內存 等資源,能夠爲容器指定資源最大容許使用量。node

更新歷史

資源請求和資源約束

能夠爲容器指定資源請求量和資源約束量。mysql

資源通常指 CPU、內存。linux

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

資源約束量,指容器要求節點限制其使用的最大容量,若是容器內存使用量超過內容約束量,容器將被殺掉,若是指定了重啓策略,容器殺掉後將被重啓。github

涉及的參數sql

約束量
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>

示例docker

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 個超線程api

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

微信掃碼關注

相關文章
相關標籤/搜索