理解resource limit 會(huì)如何影響pod 調(diào)度
Kubernetes 提供request 和 limit 兩種方式設(shè)置容器資源。
為了提高資源利用率,k8s調(diào)度時(shí)根據(jù)pod 的request值計(jì)算調(diào)度策略筋蓖,從而實(shí)現(xiàn)節(jié)點(diǎn)資源超賣。
k8s根據(jù)limit限制pod使用資源殖演,當(dāng)內(nèi)存超過(guò)limit時(shí)會(huì)觸發(fā)oom假栓。 且限制pod的cpu 不允許超過(guò)limit。
根據(jù)pod的 request和limit点晴,k8s會(huì)為pod 計(jì)算服務(wù)質(zhì)量偏形,并分為Guaranteed(requests和limits顯示設(shè)置且相等或者只設(shè)置了limits,那么requests也會(huì)與之相等), Burstable(limits和requests顯示設(shè)置不相等), BestEffort 這3級(jí)觉鼻。當(dāng)節(jié)點(diǎn)資源不足時(shí)俊扭,發(fā)生驅(qū)逐或者oom時(shí), Guaranteed 級(jí)別的pod 優(yōu)先保護(hù)坠陈, Burstable 節(jié)點(diǎn)次之(request越大萨惑,使用資源量越少 保護(hù)級(jí)別越高), BestEffort 最先被驅(qū)逐仇矾。
Kubernetes提供了RequestQuota和LimitRange 用于設(shè)置namespace 內(nèi)pod 的資源范圍 和 規(guī)挠拱總量。 RequestQuota 用于設(shè)置各種類型對(duì)象的數(shù)量贮匕, cpu和內(nèi)存的總量姐仅。 LimitRange 用于設(shè)置pod或者容器 request和limit 的默認(rèn)值,最大最小值刻盐, 以及超賣比例(limit / request)掏膏。
對(duì)于一些重要的線上應(yīng)用,我們應(yīng)該合理設(shè)置limit和request敦锌,limit和request 設(shè)置一致馒疹,資源不足時(shí)k8s會(huì)優(yōu)先保證這些pod正常運(yùn)行。
為了提高資源利用率乙墙。 對(duì)一些非核心颖变,并且資源不長(zhǎng)期占用的應(yīng)用生均,可以適當(dāng)減少pod的request,這樣pod在調(diào)度時(shí)可以被分配到資源不是十分充裕的節(jié)點(diǎn)腥刹,提高使用率马胧。但是當(dāng)節(jié)點(diǎn)的資源不足時(shí),也會(huì)優(yōu)先被驅(qū)逐或被oom kill衔峰。
不使用調(diào)度器漓雅, 手動(dòng)調(diào)度一個(gè)pod
使用static pod可以實(shí)現(xiàn)手動(dòng)調(diào)度一個(gè)pod。
static pod的特點(diǎn)總結(jié)如下:
- 不通過(guò)apiserver watch朽色, 由本機(jī)的kubelet進(jìn)程執(zhí)行watch邻吞,并拉起
- 只在本機(jī)進(jìn)行調(diào)度
- 沒(méi)有健康檢查
- 不被controller manager調(diào)度
- 因?yàn)閍piserver里有pod的鏡像信息, 通過(guò)apiserver還是可以看到pod的信息
如何創(chuàng)建葫男?
方法一: kubelet啟動(dòng)時(shí)要指定參數(shù)kubelet --pod-manifest-path=<the directory>抱冷,這里的the directory要放置static pod的編排文件的目錄。 把static pod的編排文件放到此目錄下梢褐, kubelet可以監(jiān)聽(tīng)到變化旺遮, 并根據(jù)編排文件創(chuàng)建pod。
方法二: 指定--manifest-url=<URL>盈咳, kubelet會(huì)從這個(gè)URL下載編排文件耿眉, 并創(chuàng)建pod
如何刪除?
當(dāng)我們直接用kubectl的命令kubectl delete pod刪除一個(gè)靜態(tài)pod時(shí)鱼响, 我們會(huì)發(fā)現(xiàn)static pod過(guò)一段時(shí)間又會(huì)被kubelet拉起鸣剪。
要完全刪除一個(gè)static pod, 可以移除把該static pod的編排文件丈积, 從--pod-manifest-path=<the directory>所指定的目錄里移除即可筐骇。
使用場(chǎng)景?
因?yàn)閟tatic pod有一個(gè)特性是我們的應(yīng)用的docker 容器被刪除江滨,或者pod被kubectl誤刪了之后铛纬, static pod還能被kubelet進(jìn)程拉起。通過(guò)這種方式保證了應(yīng)用的可用性唬滑。 有點(diǎn)相當(dāng)于systemd的功能告唆, 但比systemd好的一點(diǎn)是, static pod的鏡像信息會(huì)在apiserver中注冊(cè)晶密。 這樣的話擒悬, 我們就可以統(tǒng)一對(duì)部署信息進(jìn)行可視化管理。 另外static調(diào)度了的是容器惹挟, 無(wú)需拷貝二進(jìn)制文件到主機(jī)上茄螃, 應(yīng)用封裝在鏡像里也保證了環(huán)境的一致性缝驳, 無(wú)論是應(yīng)用的編排文件還是應(yīng)用的鏡像都方便進(jìn)行版本管理和分發(fā)连锯。
實(shí)際生產(chǎn)中归苍, static pod可以用來(lái)部署kubernetes的kube-proxy, kube-scheduler, kube-controller-manager, kube-apiserver等進(jìn)程。
當(dāng)我們要部署一個(gè)有狀態(tài)的應(yīng)用运怖, 有幾種方式:
- 使用statefulset
- 給主機(jī)打上label拼弃,只允許主機(jī)在這幾臺(tái)主機(jī)上調(diào)度
- 通過(guò)掛載ceph盤來(lái)存儲(chǔ)有狀態(tài)數(shù)據(jù)(要求master和node節(jié)點(diǎn)上都要安裝rbd工具)
- 使用static pod ,但是這種方式適合那些無(wú)滾動(dòng)升級(jí)需求摇展, 無(wú)擴(kuò)縮容需求吻氧,不頻繁進(jìn)行升級(jí)的應(yīng)用
常用的優(yōu)選算法介紹:
least_requested分值計(jì)算方式 (cpu((capacity-sum(requested))10/capacity) + memory((capacity-sum(requested))10/capacity))/2
其cpu和menmory分值各占一半。
balanced_resource_allocation是選用cpu和內(nèi)存使用最為接近的節(jié)點(diǎn)咏连,基于least_requested分值的計(jì)算結(jié)果判定盯孙。
那么schedule里的policy是啥樣子的呢:
{
"kind" : "Policy",
"apiVersion" : "v1",
"predicates" : [
{"name" : "PodFitsPorts"},
{"name" : "PodFitsResources"},
{"name" : "NoDiskConflict"},
{"name" : "MatchNodeSelector"},
{"name" : "HostName"}
],
"priorities" : [
{"name" : "LeastRequestedPriority", "weight" : 1},
{"name" : "BalancedResourceAllocation", "weight" : 1},
{"name" : "ServiceSpreadingPriority", "weight" : 1},
{"name" : "EqualPriority", "weight" : 1}
]
}
*** 4. controller的區(qū)別 ***
controller manager作為集群內(nèi)部的管理控制中心,負(fù)責(zé)集群內(nèi)的Node祟滴,Pod副本振惰,服務(wù)端點(diǎn)(endpoint),命名空間(namespace)等的管理垄懂,當(dāng)某個(gè)Node意外宕機(jī)骑晶,CM會(huì)及時(shí)發(fā)現(xiàn)此故障并執(zhí)行自動(dòng)化修復(fù)流程,確保集群始終處于預(yù)期的工作狀態(tài)草慧。
controller management包括:replication controller桶蛔,node controller,rescourseQuota controller漫谷,namespaces controller仔雷,serviceAccount controller,token controller舔示,service tontroller和endpoint controller朽寞。CM是這些controller的核心管理者。
Replication Controller
RC的作用是確保在任何時(shí)候集群中一個(gè)RC所關(guān)聯(lián)的Pod副本數(shù)量保持預(yù)設(shè)值斩郎。
最好不用越過(guò)RC而直接創(chuàng)建Pod脑融,因?yàn)橥ㄟ^(guò)RC管理Pod副本,實(shí)現(xiàn)自動(dòng)創(chuàng)建缩宜,補(bǔ)足肘迎,替換,刪除Pod副本锻煌,提供系統(tǒng)的容災(zāi)能力妓布。
總結(jié)一下RC的職責(zé):
1.確保當(dāng)前集群中有且僅有N個(gè)Pod實(shí)例
2.通過(guò)調(diào)整RC中yaml文件的spec.replicas屬性值來(lái)實(shí)現(xiàn)系統(tǒng)擴(kuò)容或縮容
3.通過(guò)改變RC中的Pod模板來(lái)實(shí)現(xiàn)系統(tǒng)的滾動(dòng)升級(jí)。
再總結(jié)一下RC的典型使用場(chǎng)景宋梧,如下
1.重新調(diào)度
2.彈性伸縮
3.滾動(dòng)更新
Node controller
kubelet進(jìn)程在啟動(dòng)時(shí)通過(guò)API server注冊(cè)自身節(jié)點(diǎn)信息匣沼,并定時(shí)向API server匯報(bào)狀態(tài)信息,API server更新這些信息到etcd中捂龄。
Node controller通過(guò)API server定時(shí)獲取Node的相關(guān)信息释涛,實(shí)現(xiàn)管理和監(jiān)控Node加叁。
endpoint controller 和service controller
endpoint表示了一個(gè)service對(duì)應(yīng)的所有pod副本的訪問(wèn)地址,而endpoint controller就是負(fù)責(zé)生成和維護(hù)所有endpoint對(duì)象的控制器唇撬。負(fù)責(zé)監(jiān)聽(tīng)service和對(duì)應(yīng)的Pod副本的變化它匕,若service被刪除,則刪除與該service同名的endpoint對(duì)象窖认,若檢測(cè)到新的service創(chuàng)建或修改豫柬,則先根據(jù)該service獲取相應(yīng)的pod列表,然后創(chuàng)建或更新service對(duì)應(yīng)的endpoint對(duì)象扑浸。
那么endpoint對(duì)象如何使用呢埠胖。答案是在每個(gè)node上的kube-proxy進(jìn)程子檀,該進(jìn)程獲得每個(gè)service的endpoint,實(shí)現(xiàn)service的負(fù)載均衡功能。
Namespace controller
用戶通過(guò)API server可以創(chuàng)建新的Namespace并保存在etcd中锤悄,namespace controller定時(shí)通過(guò)API server讀取這些namespace信息醋界,若namespace被刪除服鹅,則NC刪除該namespace下的RC混蔼,Pod等資源對(duì)象。
如果namespace controller觀察到namespace設(shè)置了刪除期限系奉,同時(shí)namespace的spec.finalizers域值為空檬贰,則NC將通過(guò)API server刪除該namespace資源。
ReplicaSet
ReplicaSet的目的是在任何時(shí)候都maintain一組穩(wěn)定的pod replicas缺亮,常用來(lái)確保指定數(shù)量的pod replica可用翁涤。ReplicaSet具有selector,replicas, podTemplate字段萌踱。通過(guò)pod的metadata.ownerReferences字段來(lái)關(guān)聯(lián)ReplicaSet和Pod葵礼。
注意:當(dāng)創(chuàng)建的pod的label符合ReplicaSet的selector,且該pod不屬于任何controller并鸵,則該pod會(huì)被自動(dòng)歸為該ReplicaSet擁有鸳粉,導(dǎo)致ReplicaSet下的pod不相同;同時(shí)园担,會(huì)影響ReplicaSet本身的replica pod的個(gè)數(shù)届谈。
建議使用Deployment來(lái)管理ReplicaSet,而不是直接使用弯汰,除非需要定制化的更新測(cè)例或不需要更新艰山。
因?yàn)閐eployment不僅具備了replicaSet的功能,同時(shí)還支持事件和狀態(tài)查看咏闪,回滾曙搬,版本記錄,對(duì)于每次升級(jí)可以暫停和啟動(dòng)。
Deployment
Deployment對(duì)Pod和ReplicaSet提供聲明式的更新纵装。在描述預(yù)期狀態(tài)后征讲,Deployment會(huì)以可控的頻率下使得實(shí)際狀態(tài)符合預(yù)期狀態(tài)。
默認(rèn)情況下搂擦,Deployment保證最多25%的pod不可靠稳诚,pod數(shù)量最多超出25%哗脖。
StatefulSets
StatefulSets主要用來(lái)管理有狀態(tài)的app瀑踢。跟Deployment一樣,StatefulSet用來(lái)管理Pod才避,但不同的是橱夭,StatefulSets中的每個(gè)pod都維護(hù)一個(gè)嚴(yán)格的identifier并在reschedule時(shí)不變。
StatefulSet具有以下特點(diǎn):
- Stable, unique network identifiers.
- Stable, persistent storage.
- Ordered, graceful deployment and scaling.
- Ordered, automated rolling updates.
限制:
- Pod的storage要么基于請(qǐng)求的storage class由PersistentVolume Provisioner設(shè)置桑逝,要么由admin提前設(shè)置好棘劣;
- 刪除或scale down StatefulSet將不會(huì)刪除相關(guān)的volumes,用于保證數(shù)據(jù)安全楞遏;
- StatefulSets目前需要?jiǎng)?chuàng)建headless service來(lái)負(fù)責(zé)pod的netework identity茬暇,用戶負(fù)責(zé)創(chuàng)建該headless service;
- StatefulSet刪除后不保證pod結(jié)束寡喝,pod會(huì)按順序gracefully的結(jié)束糙俗;
- 當(dāng)使用默認(rèn)的Pod Management Policy(
OrderedReady
)作為rollupdate policy,可能需要人工干預(yù)來(lái)走出broken state预鬓。 - StatefulSet上部署和擴(kuò)展的規(guī)則:創(chuàng)建pod的順序由0到N巧骚,刪除的順序正好相反;擴(kuò)展時(shí)格二,前面的pod必須是Running和Ready狀態(tài)劈彪,刪除時(shí),后續(xù)pod必須是terminated顶猜。
K8S 1.7之后沧奴,指定.spec.updateStrategy來(lái)設(shè)置更新策略,當(dāng).spec.updateStrategy.type為OnDelete時(shí)长窄,在pod template改動(dòng)后將不會(huì)自動(dòng)更新Pods扼仲;為RollingUpdate,默認(rèn)策略抄淑,將自動(dòng)更新pod屠凶。RollingUpdate更新策略可以設(shè)置partition,通過(guò)設(shè)置字段 .spec.updateStrategy.rollingUpdate.partition來(lái)實(shí)現(xiàn)肆资,當(dāng)pod template更新后矗愧,只有ordinal大于等于partition的pod才會(huì)更新,小于partition的pod不更新。當(dāng).spec.replicas小于partition唉韭,所有pod不更新夜涕。
Job
Job創(chuàng)建一個(gè)或多個(gè)pod并確保指定數(shù)量的pod成功終止。當(dāng)指定數(shù)量的pod成功終止后属愤,job結(jié)束女器。場(chǎng)景:當(dāng)創(chuàng)建的pod不能完成時(shí),job會(huì)創(chuàng)建新的pod來(lái)完成任務(wù)住诸。
下面是Job的示例驾胆。
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
backoffLimit:6
activeDeadlineSeconds: 100 #
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
restartPolicy只允許Never或OnFailure。
通過(guò)設(shè)置.spec.completions和.spec.parallelism屬性來(lái)完成不同的任務(wù)贱呐,前者表示成功完成的任務(wù)數(shù)量丧诺,后者表示并行任務(wù)數(shù)量,默認(rèn)都為1.當(dāng).spec.parallelism設(shè)置為0時(shí)奄薇,job將被暫停驳阎。
通過(guò).spec.backoffLimit來(lái)設(shè)置pod失敗后的重試次數(shù),默認(rèn)為6馁蒂,重試的delay時(shí)間指數(shù)式增長(zhǎng)呵晚,最長(zhǎng)6分鐘。
當(dāng)Job complete沫屡,將不會(huì)創(chuàng)建pod饵隙,old pod也不會(huì)被刪除,這樣可以查看log谁鳍。同時(shí)癞季,Job也存在,這樣可以查看status倘潜”疗猓可以通過(guò)kubectl delete來(lái)人工刪除。
Job終止可能因?yàn)槭〈螖?shù)超過(guò).spec.backoffLimit涮因,或者因?yàn)閖ob的運(yùn)行時(shí)間炒超過(guò)設(shè)置的.spec.activeDeadlineSeconds废睦。當(dāng)Job的運(yùn)行時(shí)間超過(guò)activeDeadlineSeconds,所有運(yùn)行的pod被終止养泡,Job狀態(tài)變?yōu)镕ailed嗜湃,reason: DeadlineExceeded。
-Cron Job
終止的Job不被回收會(huì)浪費(fèi)資源澜掩,可以使用cron job來(lái)管理job并清理job购披。
Cron Job創(chuàng)建基于時(shí)間調(diào)度的job,時(shí)區(qū)為master node的時(shí)區(qū)肩榕。當(dāng)Cron job大于100次沒(méi)有被調(diào)度刚陡,將不會(huì)調(diào)度job并打印error信息。Cron job只負(fù)責(zé)創(chuàng)建符合schedule的job,而job負(fù)責(zé)pod的管理筐乳。
activeDeadlineSeconds
通過(guò)指定job存活時(shí)間歌殃,來(lái)結(jié)束一個(gè)job。當(dāng)job運(yùn)行時(shí)間達(dá)到activeDeadlineSeconds指定的時(shí)間后蝙云,job會(huì)停止由它啟動(dòng)的所有任務(wù)(如:pod)氓皱,并設(shè)置job的狀態(tài)為failed, reason: DeadlineExceeded
TTL Controller提供了一種機(jī)制來(lái)限制resource object執(zhí)行完存活的時(shí)間,目前只處理Job勃刨。
ttlSecondsAfterFinished
使用場(chǎng)景:默認(rèn)情況下波材,job異常或者成功結(jié)束后朵你,包括job啟動(dòng)的任務(wù)(pod)各聘,都不會(huì)被清理掉揣非,因?yàn)槟憧梢砸罁?jù)保存的job和pod抡医,查看狀態(tài)、日志早敬,以及調(diào)試等忌傻。這些用戶可以手動(dòng)刪除,用戶手動(dòng)刪除job搞监,job controller會(huì)級(jí)聯(lián)刪除對(duì)應(yīng)的pod水孩。
除了手動(dòng)刪除,通過(guò)指定參數(shù)ttlSecondsAfterFinished也可以實(shí)現(xiàn)自動(dòng)刪除job琐驴,以及級(jí)聯(lián)的資源俘种,如:pod。如果設(shè)置為0绝淡,job會(huì)被立即刪除宙刘。如果不指定,job則不會(huì)被刪除牢酵。