寫在前面
當(dāng)我開始大范圍使用Kubernetes的時(shí)候,我開始考慮一個(gè)我做實(shí)驗(yàn)時(shí)沒有遇到的問題:當(dāng)集群里的節(jié)點(diǎn)沒有足夠資源的時(shí)候,Pod會(huì)卡在Pending狀態(tài)。你是沒有辦法給節(jié)點(diǎn)增加CPU或者內(nèi)存的,那么你該怎么做才能將這個(gè)Pod從這個(gè)節(jié)點(diǎn)拿走?最簡單的辦法是添加另一個(gè)節(jié)點(diǎn),我承認(rèn)我總是這么干。最終這個(gè)策略無法發(fā)揮出Kubernetes最重要的一個(gè)能力:即它優(yōu)化計(jì)算資源使用的能力。這些場景里面實(shí)際的問題并不是節(jié)點(diǎn)太小,而是我們沒有仔細(xì)為Pod計(jì)算過資源限制。
資源限制是我們可以向Kubernetes提供的諸多配置之一,它意味著兩點(diǎn):工作負(fù)載運(yùn)行需要哪些資源;最多允許消費(fèi)多少資源。第一點(diǎn)對于調(diào)度器而言十分重要,因?yàn)樗源诉x擇合適的節(jié)點(diǎn)。第二點(diǎn)對于Kubelet非常重要,每個(gè)節(jié)點(diǎn)上的守護(hù)進(jìn)程Kubelet負(fù)責(zé)Pod的運(yùn)行健康狀態(tài)。大多數(shù)本文的讀者可能對資源限制有一定的了解,實(shí)際上這里面有很多有趣的細(xì)節(jié)。在這個(gè)系列的兩篇文章中我會(huì)先仔細(xì)分析內(nèi)存資源限制,然后第二篇文章中分析CPU資源限制。
資源限制
資源限制是通過每個(gè)容器containerSpec的resources字段進(jìn)行設(shè)置的,它是v1版本的ResourceRequirements類型的API對象。每個(gè)指定了"limits"和"requests"的對象都可以控制對應(yīng)的資源。目前只有CPU和內(nèi)存兩種資源。第三種資源類型,持久化存儲(chǔ)仍然是beta版本,我會(huì)在以后的博客里進(jìn)行分析。大多數(shù)情況下,deployment、statefulset、daemonset的定義里都包含了podSpec和多個(gè)containerSpec。這里有個(gè)完整的v1資源對象的yaml格式配置:
這個(gè)對象可以這么理解:這個(gè)容器通常情況下,需要5%的CPU時(shí)間和50MiB的內(nèi)存(requests),同時(shí)最多允許它使用10%的CPU時(shí)間和100MiB的內(nèi)存(limits)。我會(huì)對requests和limits的區(qū)別做進(jìn)一步講解,但是一般來說,在調(diào)度的時(shí)候requests比較重要,在運(yùn)行時(shí)limits比較重要。盡管資源限制配置在每個(gè)容器上,你可以認(rèn)為Pod的資源限制就是它里面容器的資源限制之和,我們可以從系統(tǒng)的視角觀察到這種關(guān)系。
內(nèi)存限制
通常情況下分析內(nèi)存要比分析CPU簡單一些,所以我從這里開始著手。我的一個(gè)目標(biāo)是給大家展示內(nèi)存在系統(tǒng)中是如何實(shí)現(xiàn)的,也就是Kubernetes對容器運(yùn)行時(shí)(docker/containerd)所做的工作,容器運(yùn)行時(shí)對Linux內(nèi)核所做的工作。從分析內(nèi)存資源限制開始也為后面分析CPU打好了基礎(chǔ)。首先,讓我們回顧一下前面的例子:
單位后綴Mi表示的是MiB,所以這個(gè)資源對象定義了這個(gè)容器需要50MiB并且最多能使用100MiB的內(nèi)存。當(dāng)然還有其他單位可以進(jìn)行表示。為了了解如何用這些值是來控制容器進(jìn)程,我們首先創(chuàng)建一個(gè)沒有配置內(nèi)存限制的Pod:
$ kubectl run limit-test --image=busybox --command -- /bin/sh -c "while true; do sleep 2; done"
deployment.apps "limit-test" created
用Kubectl命令我們可以驗(yàn)證這個(gè)Pod是沒有資源限制的:
$ kubectl get pods limit-test-7cff9996fc-zpjps -o=jsonpath='{.spec.containers[0].resources}'
map[]
Kubernetes最酷的一點(diǎn)是你可以跳到系統(tǒng)以外的角度來觀察每個(gè)構(gòu)成部分,所以我們登錄到運(yùn)行Pod的節(jié)點(diǎn),看看Docker是如何運(yùn)行這個(gè)容器的:
$ docker ps | grep busy | cut -d' ' -f1
5c3af3101afb
$ docker inspect 5c3af3101afb -f "{{.HostConfig.Memory}}"
這個(gè)容器的.HostConfig.Memory域?qū)?yīng)了docker run時(shí)的--memory參數(shù),0值表示未設(shè)定。Docker會(huì)對這個(gè)值做什么?為了控制容器進(jìn)程能夠訪問的內(nèi)存數(shù)量,Docker配置了一組control group,或者叫cgroup。Cgroup在2008年1月時(shí)合并到Linux 2.6.24版本的內(nèi)核。它是一個(gè)很重要的話題。我們說cgroup是容器的一組用來控制內(nèi)核如何運(yùn)行進(jìn)程的相關(guān)屬性集合。針對內(nèi)存、CPU和各種設(shè)備都有對應(yīng)的cgroup。Cgroup是具有層級(jí)的,這意味著每個(gè)cgroup擁有一個(gè)它可以繼承屬性的父親,往上一直直到系統(tǒng)啟動(dòng)時(shí)創(chuàng)建的root cgroup。
Cgroup可以通過/proc和/sys偽文件系統(tǒng)輕松查看到,所以檢查容器如何配置內(nèi)存的cgroup就很簡單了。在容器的Pid namespace里,根進(jìn)程的pid為1,但是namespace以外它呈現(xiàn)的是系統(tǒng)級(jí)pid,我們可以用來查找它的cgroups:
*$ ps ax | grep /bin/sh
9513 ? Ss 0:00 /bin/sh -c while true; do sleep 2; done
$ sudo cat /proc/9513/cgroup
...
6:memory:/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574
*
我列出了內(nèi)存cgroup,這正是我們所關(guān)注的。你在路徑里可以看到前面提到的cgroup層級(jí)。一些比較重要的點(diǎn)是:首先,這個(gè)路徑是以kubepods開始的cgroup,所以我們的進(jìn)程繼承了這個(gè)group的每個(gè)屬性,還有burstable的屬性(Kubernetes將Pod設(shè)置為burstable QoS類別)和一組用于審計(jì)的Pod表示。最后一段路徑是我們進(jìn)程實(shí)際使用的cgroup。我們可以把它追加到/sys/fs/cgroups/memory后面查看更多信息:
$ ls -l /sys/fs/cgroup/memory/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574
...
-rw-r--r-- 1 root root 0 Oct 27 19:53 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Oct 27 19:53 memory.soft_limit_in_bytes
再一次,我只列出了我們所關(guān)心的記錄。我們暫時(shí)不關(guān)注memory.soft_limit_in_bytes,而將重點(diǎn)轉(zhuǎn)移到memory.limit_in_bytes屬性,它設(shè)置了內(nèi)存限制。它等價(jià)于Docker命令中的--memory參數(shù),也就是Kubernetes里的內(nèi)存資源限制。我們看看:
$ sudo cat /sys/fs/cgroup/memory/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574/memory.limit_in_bytes
9223372036854771712
這是沒有設(shè)置資源限制時(shí)我的節(jié)點(diǎn)上顯示的情況。這里有對它的一個(gè)簡單的解釋(https://unix.stackexchange.com/questions/420906/what-is-the-value-for-the-cgroups-limit-in-bytes-if-the-memory-is-not-restricte)。所以我們看到如果沒有在Kubernetes里設(shè)置內(nèi)存限制的話,會(huì)導(dǎo)致Docker設(shè)置HostConfig.Memory值為0,并進(jìn)一步導(dǎo)致容器進(jìn)程被放置在默認(rèn)值為"no limit"的memory.limit_in_bytes內(nèi)存cgroup下。我們現(xiàn)在創(chuàng)建使用100MiB內(nèi)存限制的Pod:
$ kubectl run limit-test --image=busybox --limits "memory=100Mi" --command -- /bin/sh -c "while true; do sleep 2; done"
deployment.apps "limit-test" created
我們再一次使用kubectl驗(yàn)證我們的資源配置:
$ kubectl get pods limit-test-5f5c7dc87d-8qtdx -o=jsonpath='{.spec.containers[0].resources}'
map[limits:map[memory:100Mi] requests:map[memory:100Mi]]
你會(huì)注意到除了我們設(shè)置的limits外,Pod還增加了requests。當(dāng)你設(shè)置limits而沒有設(shè)置requests時(shí),Kubernetes默認(rèn)讓requests等于limits。如果你從調(diào)度器的角度看這是非常有意義的。我會(huì)在下面進(jìn)一步討論requests。當(dāng)這個(gè)Pod啟動(dòng)后,我們可以看到Docker如何配置的容器以及這個(gè)進(jìn)程的內(nèi)存cgroup:
$ docker ps | grep busy | cut -d' ' -f1
8fec6c7b6119
$ docker inspect 8fec6c7b6119 --format '{{.HostConfig.Memory}}'
104857600
$ ps ax | grep /bin/sh
29532 ? Ss 0:00 /bin/sh -c while true; do sleep 2; done
$ sudo cat /proc/29532/cgroup
...
6:memory:/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11
$ sudo cat /sys/fs/cgroup/memory/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11/memory.limit_in_bytes
104857600
正如你所見,Docker基于我們的containerSpec正確地設(shè)置了這個(gè)進(jìn)程的內(nèi)存cgroup。但是這對于運(yùn)行時(shí)意味著什么?Linux內(nèi)存管理是一個(gè)復(fù)雜的話題,Kubernetes工程師需要知道的是:當(dāng)一個(gè)宿主機(jī)遇到了內(nèi)存資源壓力時(shí),內(nèi)核可能會(huì)有選擇性地殺死進(jìn)程。如果一個(gè)使用了多于限制內(nèi)存的進(jìn)程會(huì)有更高幾率被殺死。因?yàn)镵ubernetes的任務(wù)是盡可能多地向這些節(jié)點(diǎn)上安排Pod,這會(huì)導(dǎo)致節(jié)點(diǎn)內(nèi)存壓力異常。如果你的容器使用了過多內(nèi)存,那么它很可能會(huì)被oom-killed。如果Docker收到了內(nèi)核的通知,Kubernetes會(huì)找到這個(gè)容器并依據(jù)設(shè)置嘗試重啟這個(gè)Pod。
所以Kubernetes默認(rèn)創(chuàng)建的內(nèi)存requests是什么?擁有一個(gè)100MiB的內(nèi)存請求會(huì)影響到cgroup?可能它設(shè)置了我們之前看到的memory.soft_limit_in_bytes?讓我們看看:
$ sudo cat /sys/fs/cgroup/memory/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11/memory.soft_limit_in_bytes
9223372036854771712
你可以看到軟限制仍然被設(shè)置為默認(rèn)值“no limit”。即使Docker支持通過參數(shù)--memory-reservation進(jìn)行設(shè)置,但Kubernetes并不支持這個(gè)參數(shù)。這是否意味著為你的容器指定內(nèi)存requests并不重要?不,不是的。requests要比limits更重要。limits告訴Linux內(nèi)核什么時(shí)候你的進(jìn)程可以為了清理空間而被殺死。requests幫助Kubernetes調(diào)度找到合適的節(jié)點(diǎn)運(yùn)行Pod。如果不設(shè)置它們,或者設(shè)置得非常低,那么可能會(huì)有不好的影響。
例如,假設(shè)你沒有配置內(nèi)存requests來運(yùn)行Pod,而配置了一個(gè)較高的limits。正如我們所知道的Kubernetes默認(rèn)會(huì)把requests的值指向limits,如果沒有合適的資源的節(jié)點(diǎn)的話,Pod可能會(huì)調(diào)度失敗,即使它實(shí)際需要的資源并沒有那么多。另一方面,如果你運(yùn)行了一個(gè)配置了較低requests值的Pod,你其實(shí)是在鼓勵(lì)內(nèi)核oom-kill掉它。為什么?假設(shè)你的Pod通常使用100MiB內(nèi)存,你卻只為它配置了50MiB內(nèi)存requests。如果你有一個(gè)擁有75MiB內(nèi)存空間的節(jié)點(diǎn),那么這個(gè)Pod會(huì)被調(diào)度到這個(gè)節(jié)點(diǎn)。當(dāng)Pod內(nèi)存消耗擴(kuò)大到100MiB時(shí),會(huì)讓這個(gè)節(jié)點(diǎn)壓力變大,這個(gè)時(shí)候內(nèi)核可能會(huì)選擇殺掉你的進(jìn)程。所以我們要正確配置Pod的內(nèi)存requests和limits。
相關(guān)服務(wù)請?jiān)L問:
https://support.huaweicloud.com/cce/index.html?utm_content=cce_helpcenter_2019
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
名稱欄目:深入理解Kubernetes資源限制:內(nèi)存-創(chuàng)新互聯(lián)
鏈接分享:http://jinyejixie.com/article12/dhdhdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站設(shè)計(jì)公司、營銷型網(wǎng)站建設(shè)、軟件開發(fā)、移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容