Node隔離與恢復
- cat unschedule_node.yaml
apiVersion:
kind: Node
metadata:
name: k8s-node-1
labels:
kubernetes.io/hostname: k8s-node-1
sepc:
unschedulable: true
- kubectl replace -f unschedule_node.yaml
- kubectl patch node k8s-node-a -p '{"spec":{"unschedulable":"true"}'
- kubectl cordon k8s-node-1(對節點進行隔離)
- kubectl uncordon k8s-node-1(對節點進行恢復)
Node的擴容
在新節點上安裝Docker、kubelet、kube-proxy服務,並修改kubelet和kube-proxy的啟動參數將Master URL指定為當前集群的Master的地址,最后啟動這些服務。
更新資源對象的Label
- kubectl lable pod redis-master-bobr role=backend
- kubectl get pods -Lrole
- kubectl label pod redis-master-bobr0 role-
- kubectl label pod redis-master-bobr0 role=master --overwrite(對標簽進行修改的時候需要加上參數--overwrite)
Namespace:集群環境共享與隔離
在一個組織內部,不同的工作組可以在統一個Kubernetes集群中工作,Kubernetes通過命名空間和Context的設置來對不同的工作組進行區分,使得他們既可以共享同一個Kubernetes集群的服務,也能夠互不干擾。
創建namespace
- cat namespace-development.yaml(創建namespace)
apiVersion: v1
kind: Namespace
metadata:
name: development
- cat namespace-production.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
- kubectl create -f namespace-development.yaml
- kubectl create -f namespace-production.yaml
- kubectl get namespace
定義Content(運行環境)
接下來需要為這兩個工作組分別定義一個Content,即運行環境。這個運行環境將屬於某個特定的命名空間。
通過kubectl config set-context命令定義Context,並將Context置於之前創建的命名空間中:
- kubectl config set-cluster kubernetes-cluster --server=https://192.168.1.128:8080
- kubectl config set-context ctx-dev --namespace=development --cluster=kubernetes-cluster --user=dev
- kubectl config set-context ctx-prod --namespace=production --cluster=kubernetes-cluster --user=prod
可使用kubectl config view命令查看已定義的Context
當然也可以通過編輯文件的方式來設置Context:
- cat Context-config.yaml
apiVersion: v1
clusters:
- clusters:
server: http://192.168.1.128:8080
name: kubernetes-cluster
contexts:
- context:
cluster: kubernetes-cluster
namespace: development
name: ctx-dev
- context:
cluster: kubernetes-cluster
namespace: production
name: ctx-prod
current-context: ctx-dev
kind: Config
preference: { }
users: [ ]
設置工作組在特定Context環境中工作
使用kubectl config use-context <context_name>命令來設置當前的運行環境。
- kubectl config use-context ctx-dev(把當前工作環境設置為ctx-dev,進行工作環境的切換)
Kubernetes資源管理
下面將從計算資源管理(Compute Resource)、資源配置范圍管理(LimitRange)、服務質量管理(Qos)及資源配額管理(ResourceQuota)等方面,對Kubernetes集群內的資源管理進行詳細說明。
計算資源管理(Compute Resources)
- 資源請求(Resource Request)可完全保證的資源量,Request的值會提供給Kubernetes Scheduler便於優化基於資源請求的容器調度;
- 資源限制(Resource Limits)最多能使用到的資源上限,這個上限值會影響發生資源競爭時的解決策略;
- CPU(Cores)(0.1CPU=100m)單獨說一下spec.container[].resources.limits.cpu到配置在docker中的實際運行情況:首先會將配置的CPU的值轉換成millicore(比如配置的是1,轉換成1000,配置的100m轉換成100),將此配置的值乘以100000,除以1000,然后再講結果作為--cpu-quota參數的值傳遞給docker run命令,docker run命令中另外一個參數是--cpu-period默認值是100000,表示
- Docker重新計量和分配CPU的使用時間間隔100000微妙(100毫秒)。Docker的--cpu-quota參數和--cpu-period參數一起配合完成對容器CPU的使用限制。比如Kubernetes中配置容器的CPU Limits為0.1,那么計算后的--cpu-quota為10000,而--cpu-period為100000,這以為着Docker在100毫秒內最多給該容器分配10毫秒的*core的計算資源用量。其結果與Kubernetes配置的意義是一致的。
- Memory(Bytes)(KiB與MiB是二進制表示的字節單位,常見的KB與MB是十進制表示的字節單位:1KB=1000bytes=8000bits、1KiB=2^10bytes=1024byte=8192bits
- )
- 區別於API資源(API Resources,如Pod和Service等)
盡管Requests和Limits只能設置到容器上,但是設置Pod級別的Reuests和Limits能極大程度上提高我們隊Pod管理的便利性和靈活性,因此Kubernetes中提供對Pod級別的Requests和Limits配置。對於CPU和內存而言,Pod的Reusets或Limits是指該Pod中所有容器的Requests或Limits的總和(Pod中沒設置Request或Limits的容器,該項的值為0或者按照集群配置的默認值來計算)
計算資源使用情況監控
Pod的資源用量會作為Pod的狀態信息一同上報給Master。如果集群中配置了Heapster來監控集群的性能數據,那么還可以從Heapster中查看Pod的資源用量信息。
計算資源相關常見問題分析
- kubectl describe pod frontend | grep -A 3 Events(查看調度失敗的原因)
- 若由於資源問題造成的調度失敗,則可采用以下幾個方案進行解決:
- 添加更多的節點到集群中;
- 停止一些不必要運行中的Pod,釋放資源;
- 檢查Pod資源的配置有無錯誤;
- kubectl describe nodes k8s-node-1
- kubectl get pod -o(讀取已經終止容器之前的狀態信息)
計算資源管理的演進
資源的配置管理范圍
對集群內Request和Limits的配置做一個全局的統一的限制:
- 集群中每個節點2GB內存,禁止Pod申請超過2GB內存;
- 為不同的命名空間設置不同的限制來滿足要求;
- 集群中每個Pod必須至少使用集群平均資源的值(CPU和內存)的20%。這樣集群能夠提供更好的資源一致性的調度,從而減少資源的浪費;
- kubectl create namespace limit-example
- cat limits.yaml
apiVersion: V1
kind: LimitRange
metadata:
name: mylimits
spec:
limits:
- max:
cpu: "4"
memory: 2Gi
min:
cpu: 20m
memory: 6Mi
maxLimitRequestRatio:
cpu: 3
memory: 2
type: Pod
- - defaultLimits:
cpu: 300m
memory: 200Mi
defaultRequest:
cpu: 200m
memory: 100Mi
max:
cpu: 2
memory:1Gi
min:
cpu: 100m
memory: 3Mi
maxLimitRequestsRatio:
cpu: 5
memory: 4
type: Container
- kubectl create -f limits.yaml --namespace=limit-example
- kubectl describe limits mylimits --namespace=limit-example
- 不論CPU還是內存,在LimitRange中,Pod和Container都可以設置Min、Max和Max Limit/Request Ratio這三種參數。Container還可以設置Default Request和Default Limit這兩種參數,而Pod不能設置Default Request和Default Limit。
- 對Pod和Container的五種參數的解釋如下:
- Container的Min是Pod中所由容器的Requests值的下限;Container的Max是Pod中所有容器Limits值的上限;Container的Default Request是Pod中所有未指定Requests值的容器的默認Request;Container的Default Limit是Pod中所有未指定Limits值的容器的默認Limits值。對於同一資源類型Min<=Default Request<=Default Limit<=Max;
- Pod的Min是Pod中所有容器的Requests值的總和的下限;Pod的Max是Pod中所有容器的Limits值的總和的上限。當容器未指定Request值或者Limits,將使用容器的Default Request值或者Default Limit值;
- Container的Max Limit/Request Ratio限制了Pod中所有容器的Limits值與Request值的比例上限;而Pod的Max Limit/Request Ratio限制了Pod中所有容器的Limits值總和與Request值總和的比例上限;
- 如果設置了Container的Max,那么對於該類資源而言,整個集群中的所有容器都必須設置Limits,否則將無法成功創建。Pod中的容器未配置Limits時,將使用Default Limit的值,而如果Default也未配置則無法成功創建;
- 如果設置了Container的Min,那么對於該類資源而言,整個集群中的所有容器都必須設置Requests。如果創建容器時未配置該類資源的Requests,那么創建過程會報驗證錯誤。Pod里的容器的Request在未配置時,可以使用DefaultRequest;而如果又沒配置DefaultRequest,那么會默認等同於該容器的Limits;如果此時Limits也未定義,那么就會報錯;
- 對於任意一個Pod而言,該Pod中所有容器的Request總和必須大於或等於6Mi,而且所有容器的總和必須小於或等於1Gi;同樣所有容器的CPU Request總和必須大於或等於200m,而且所有容器的Limits總和必須小於或等於2;
- Pod里任何容器的Limits與Requests的比例不能超過Container的Max Limit/Requests Ratio;Pod里所有的Limits總和與Request的總和的比例不能超過Pod的Max Limit/Request Ratio;
需要注意的是,CPU Limits強制配置這個選項在Kubernetes集群中默認是開啟的,除非集群管理員在部署kubelet時,通過設置參數--cpu-cfs-quota=false來關閉該限制;
- kubelet --cpu-cfs-quota=false
資源的服務質量管理(Resource QoS)
- 可壓縮資源(CPU)
- Kubernetes目前支持的可壓縮資源是CPU
- 由於目前Kubernetes和Docker的CPU隔離機制都是在容器級別隔離,所以Pod級別的資源配置並不能完全得到保障;(后續版本有無對cgroups的開發實現對Pod級別的資源精確控制)
- 空閑CPU資源按照容器Request值的比例進行分配;
- 如果Pod CPU使用量超過Limits中的值,那么cgroup會對CPU使用進行限流;如果Pod沒有配置Limits值,那么Pod會嘗試搶占所有空閑的CPU資源(因此默認情況下必須配置Limits)
- 不可壓縮資源(內存)
- 如果Pod內存的使用量小於它的Request值,那么這個Pod是可以正常運行的(除非出現操作系統級別的內存不足等嚴重的問題);如果Pod的內存使用量超過了它的Request值,那么這個Pod有可能會被Kubernetes干掉;比如Pod A使用了超過Request的值而不到Limits的內存量,此時同一個機器上另外一個Pod B向系統申請的總量不超過自己的Request值的內存,那么Kubernetes可能會直接干掉Pod A;如果Pod使用的內存量超過了它的Limits設置,那么操作系統內核會殺掉Pod所有容器的所有進程中使用內存最多的一個,知道內存不超過Limits為止;
- 對調度策略的影響
服務質量等級(QoS Classes)
在一個超用(Over Committed)系統中存在三個QoS等級:
- Guaranteed:Limits值和Request值全部相等;
- Best-Effort:Pod中所有容器都未定義資源配置;
- Burstable:既不是Guaranteed或者Best-Effort;
Kubernetes QoS的工作特點
Pod的CPU Request無法得到滿足(比如節點的系統級任務占用較多的CPU導致無法分配給足夠的CPU給容器使用)時,容器得到的CPU會被壓縮限流;
內存由於是不可壓縮資源,所以針對內存資源緊張的情況會按以下邏輯處理:
- Best-Effort Pod
- Burstable Pod
- Guaranteed
OOM計分系統
OOM(Out Of Memory)計分規則包括如下內容:
- OOM計分是進程消耗內存在系統中占的百分比中不含百分號的數字乘以十的結果,這個結果是進程OOM基礎分;將進程OOM基礎分的分值再加上這進程的OOM分數調整值OOM_SCORE_ADJ的值作為進程OOM最終分值(除root啟動的進程外)。在系統發生OOM時,OOM Killer會優先殺掉OOM計分更高的進程;
- 進程的OOM計分的基本分數值的范圍0~1000,如果A進程的調整值OOM_SCORE_ADJ減去B進程的調整值結果大於1000,那么A進程的OOM計分最終值必然大於B進程,A進程會比B進程優先被殺死;
- 不論調整值OOM_SCORE_ADJ為多少,任何進程的最終分值范圍也是1000;
- Best-Effort Pod設置OOM_SCORE_ADJ調整值為1000,因此Best-Effort Pod中的容器里面的進程OOM最終分值肯定是1000;
- Guaranteed Pod設置OOM_SCORE_ADJ調整值為-998,因此Guaranteed Pod中的容器里面的進程的OOM最終分一般為0或1;
- Burstable Pod規則分情況說明:如果Burstable Pod的內存Requests超過了系統可用內存的99.8%,那么這個Pod的OOM_SCORE_ADJ調整值固定為2;否則OOM_SCORE_ADJ調整值為1000~10(內存Request占系統可用內存的百分比的無百分號的數字部分的值),而如果內存Request為0,那么OOM_SCORE_ADJ調整值固定為999。如果一個Burstable Pod內部有多個進程的多個容器發生內存競爭沖突時,那么此時的OOM評分只能作為參考,不能保證完全按照資源配置的定義來執行OOM Kill;
OOM還有一個特殊的計分規則:
- kubelet進程和Docker進程的調整值OOM_SCORE_ADJ為-998;
- 如果配置進程調整值OOM_SCORE_ADJ為-999,那么這類進程不會被OOM Kill殺掉;
QoS的演進
更豐富的QoS策略
資源的配額管理
- Master中開啟資源配額選型
- 配額的作用域(Quota Scopes)
- 在資源配額(ResourceQuota)中設置Request和Limits
- 資源配額定義(ResourceQuota)
例子:
- kubectl create namespace myspace
- cat compute-resource.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
- kubectl create -f compute-resources.yaml --namespace=myspace
- cat object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmap: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services.loadbalancers: "2"
- kubectl create -f object-counts.yaml
- kubectl describe quota compute-resroutces --namespace=myspace
- kubectl describe quota object-counts --namespace=myspace
資源配額與集群資源總量的關系
資源配額與集群資源總量是完全獨立的。資源配額是通過絕對的單位來配置的;意味着集群中節點的添加並不會自動更新資源配額,而資源所對應的命名空間下對象也不能自動的增加資源上限。
我們希望資源配額可以支持更復雜的策略:
- 對於不同的租戶,按照比例划分集群的資源;
- 允許每個租戶都能按照需要來提高資源用量,但是有一個較寬裕的限制,以防止意外的資源耗盡的情況發生;
- 探測某個命名空間的需求,添加物理節點並擴大資源配額值;
這些策略可以通過將資源配額作為一個控制模塊,手動編寫一個控制器(controller)來監控資源使用情況,並調整命名空間上的資源配額方式來實現。
資源配額將整個集群中的資源總量做一個靜態的划分,但它並沒有對集群中的節點(Node)做任何限制,不同命名空間的Pod仍然可以運行在同一個節點之上;
(未完待續)——
