真棒!3 種方法限制 Pod 磁盤容量,瞬間豁然開朗

Pod 如何使用磁盤
容器在運(yùn)行期間會(huì)產(chǎn)生臨時(shí)文件、日志。如果沒(méi)有任何配額機(jī)制,則某些容器可能很快將磁盤寫滿,影響宿主機(jī)內(nèi)核和所有應(yīng)用。
容器的臨時(shí)存儲(chǔ),例如 emptyDir,位于目錄/var/lib/kubelet/pods 下:
/var/lib/kubelet/pods/
└── ac0810f5-a1ce-11ea-9caf-00e04c687e45 # POD_ID
├── containers
│ ├── istio-init
│ │ └── 32390fd7
│ ├── istio-proxy
│ │ └── 70ed81da
│ └── zookeeper
│ └── e9e21e59
├── etc-hosts # 命名空間的Host文件
└── volumes # Pod的卷
├── kubernetes.io~configmap # ConfigMap類型的卷
│ └── istiod-ca-cert
│ └── root-cert.pem -> ..data/root-cert.pem
├── kubernetes.io~downward-api
│ └── istio-podinfo
│ ├── annotations -> ..data/annotations
│ └── labels -> ..data/labels
├── kubernetes.io~empty-dir # Empty類型的卷
│ ├── istio-data
│ └── istio-envoy
│ ├── envoy-rev0.json
│ └── SDS
├── kubernetes.io~rbd # RBD卷
│ └── pvc-644a7e30-845e-11ea-a4e1-70e24c686d29 # /dev/rbd0掛載到這個(gè)掛載點(diǎn)
├── kubernetes.io~csi # CSI卷
└── kubernetes.io~secret # Secret類型的卷
└── default-token-jp4n8
├── ca.crt -> ..data/ca.crt
├── namespace -> ..data/namespace
└── token -> ..data/token
持久卷的掛載點(diǎn)也位于/var/lib/kubelet/pods 下,但是不會(huì)導(dǎo)致存儲(chǔ)空間的消耗。
容器的日志,存放在/var/log/pods 目錄下。
使用 Docker 時(shí),容器的 rootfs位于/var/lib/docker 下,具體位置取決于存儲(chǔ)驅(qū)動(dòng)。
Pod 驅(qū)逐機(jī)制
磁盤容量不足觸發(fā)的驅(qū)逐
具體細(xì)節(jié)參考:/kubernetes-study-note#out-of-resource[1]。
當(dāng)不可壓縮資源(內(nèi)存、磁盤)不足時(shí),節(jié)點(diǎn)上的 Kubelet 會(huì)嘗試驅(qū)逐掉某些 Pod,以釋放資源,防止整個(gè)系統(tǒng)受到影響。
其中,磁盤資源不足的信號(hào)來(lái)源有兩個(gè):
-
imagefs:容器運(yùn)行時(shí)用作存儲(chǔ)鏡像、可寫層的文件系統(tǒng) -
nodefs:Kubelet 用作卷、守護(hù)進(jìn)程日志的文件系統(tǒng)
當(dāng) imagefs 用量到達(dá)驅(qū)逐閾值,Kubelet 會(huì)刪除所有未使用的鏡像,釋放空間。
當(dāng) nodefs 用量到達(dá)閾值,Kubelet 會(huì)選擇性的驅(qū)逐 Pod(及其容器)來(lái)釋放空間。
本地臨時(shí)存儲(chǔ)觸發(fā)的驅(qū)逐
較新版本的 K8S 支持設(shè)置每個(gè) Pod 可以使用的臨時(shí)存儲(chǔ)的 request/limit,驅(qū)逐行為可以更具有針對(duì)性。
如果 Pod 使用了超過(guò)限制的本地臨時(shí)存儲(chǔ),Kubelet 將設(shè)置驅(qū)逐信號(hào),觸發(fā) Pod 驅(qū)逐流程:
-
對(duì)于容器級(jí)別的隔離,如果一個(gè)容器的可寫層、日志占用磁盤超過(guò)限制,則 Kubelet 標(biāo)記 Pod 為待驅(qū)逐 -
對(duì)于 Pod 級(jí)別的隔離,Pod 總用量限制,是每個(gè)容器限制之和。如果各容器用量之和+Pod 的 emptyDir 卷超過(guò) Pod 總用量限制,標(biāo)記 Pod 為待驅(qū)逐
從編排層限制
從 K8S 1.8 開始,支持本地臨時(shí)存儲(chǔ)(local ephemeral storage),ephemeral 的意思是,數(shù)據(jù)的持久性(durability)不做保證。臨時(shí)存儲(chǔ)可能 Backed by 本地 Attach 的可寫設(shè)備,或者內(nèi)存。
Pod 可以使用本地臨時(shí)存儲(chǔ)來(lái)作為暫存空間,或者存放緩存、日志。Kubelet 可以利用本地臨時(shí)存儲(chǔ),將 emptyDir 卷掛載給容器。Kubelet 也使用本地臨時(shí)存儲(chǔ)來(lái)保存節(jié)點(diǎn)級(jí)別的容器日志、容器鏡像、容器的可寫層。
Kubelet 會(huì)將日志寫入到你配置好的日志目錄,默認(rèn) /var/log。其它文件默認(rèn)都寫入到 /var/lib/kubelet。在典型情況下,這兩個(gè)目錄可能都位于宿主機(jī)的 rootfs 之下。
Kubernetes 支持跟蹤、保留/限制 Pod 能夠使用的本地臨時(shí)存儲(chǔ)的總量。
限制 Pod 用量
打開特性開關(guān):LocalStorageCapacityIsolation,可以限制每個(gè) Pod 能夠使用的臨時(shí)存儲(chǔ)的總量。
注意:以內(nèi)存為媒介(tmpfs)的 emptyDir,其用量計(jì)入容器內(nèi)存消耗,而非本地臨時(shí)存儲(chǔ)消耗。
使用類似限制內(nèi)存、CPU 用量的方式,限制本地臨時(shí)存儲(chǔ)用量:
spec.containers[].resources.limits.ephemeral-storage
spec.containers[].resources.requests.ephemeral-storage
單位可以是 E, P, T, G, M, K,或者 Ei, Pi, Ti, Gi, Mi, Ki(1024)。
下面這個(gè)例子,Pod 具有兩個(gè)容器,每個(gè)容器最多使用 4GiB 的本地臨時(shí)存儲(chǔ):
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
- name: wp
image: wordpress
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
對(duì) Pod 用量的監(jiān)控
不監(jiān)控
如果禁用 Kubelet 對(duì)本地臨時(shí)存儲(chǔ)的監(jiān)控,則 Pod 超過(guò) limit 限制后不會(huì)被驅(qū)逐。但是,如果磁盤整體上容量太低,節(jié)點(diǎn)會(huì)被打上污點(diǎn),所有不能容忍此污點(diǎn)的 Pod 都會(huì)被驅(qū)逐。
周期性掃描
Kubelet 可以執(zhí)行周期性的掃描,檢查 emptyDir 卷、容器日志目錄、可寫容器層,然后計(jì)算 Pod/容器使用了多少磁盤。
這個(gè)模式下有個(gè)問(wèn)題需要注意,Kubelet不會(huì)跟蹤已刪除文件的描述符。也就是說(shuō),如果你創(chuàng)建一個(gè)文件,打開文件,寫入 1GB,然后刪除文件,這種情況下 inode 仍然存在(直到你關(guān)閉文件),空間仍然被占用,但是 Kubelet 卻沒(méi)有算這 1GB.
Project Quotas
此特性在 1.15+處于 Alpha 狀態(tài)。
Project quotas 是 Linux 操作系統(tǒng)級(jí)別的特性,用于在目錄級(jí)別限制磁盤用量。只有本地臨時(shí)存儲(chǔ)(例如 emptyDir)的后備(Backing)文件系統(tǒng)支持 Project quotas,才可以使用該特性。XFS、ext4 都支持 Project quotas。
K8S 將占用從 1048576 開始的 Project ID,占用中的 ID 注冊(cè)在/etc/projects、/etc/projid 文件中。如果系統(tǒng)中其它進(jìn)程占用 Project ID,則也必須在這兩個(gè)文件中注冊(cè),這樣 K8S 才會(huì)改用其它 ID。
Quotas 比周期性掃描快,而且更加精準(zhǔn)。當(dāng)一個(gè)目錄被分配到一個(gè) Project 中后,該目錄中創(chuàng)建的任何文件,都是在 Project 中創(chuàng)建的。為了統(tǒng)計(jì)用量,內(nèi)核只需要跟蹤 Project 中創(chuàng)建了多少 block 就可以了。
如果文件被創(chuàng)建、然后刪除,但是它的文件描述符仍然處于打開狀態(tài),這種情況下,它仍然消耗空間,不會(huì)出現(xiàn)周期性掃描的那種漏統(tǒng)計(jì)的問(wèn)題。
要啟用 Project Quotas,你需要:
-
開啟 Kubelet 特性開關(guān):
LocalStorageCapacityIsolationFSQuotaMonitoring -
確保文件系統(tǒng)支持 Project quotas:
-
XFS 文件系統(tǒng)默認(rèn)支持,不需要操作
-
ext4 文件系統(tǒng),你需要在未掛載之前,啟用:
$ sudo tune2fs -O project -Q prjquota /dev/vda -
確保文件系統(tǒng)掛載時(shí),啟用了 Project quotas。使用掛載選項(xiàng)
prjquota
inode 耗盡問(wèn)題
有的時(shí)候,我們會(huì)發(fā)現(xiàn)磁盤寫入時(shí)會(huì)報(bào)磁盤滿,但是 df 查看容量并沒(méi)有 100%使用,此時(shí)可能只是因?yàn)?inode 耗盡造成的。
當(dāng)前 k8s 并不支持對(duì) Pod 的臨時(shí)存儲(chǔ)設(shè)置 inode 的 limits/requests。
但是,如果 node 進(jìn)入了 inode 緊缺的狀態(tài),kubelet 會(huì)將 node 設(shè)置為 under pressure,不再接收新的 Pod 請(qǐng)求。
從容器引擎限制
Docker 提供了配置項(xiàng) --storage-opt,可以限制容器占用磁盤空間的大小,此大小影響鏡像和容器文件系統(tǒng),默認(rèn) 10G。
你也可以在 /etc/docker/daemon.json 中修改此配置項(xiàng):
{
"storage-driver": "devicemapper",
"storage-opts": [
// devicemapper
"dm.basesize=20G",
// overlay2
"overlay2.size=20G",
]
}
但是這種配置無(wú)法影響那些掛載的卷,例如 emptyDir。
從系統(tǒng)層限制
你可以使用 Linux 系統(tǒng)提供的任何能夠限制磁盤用量的機(jī)制,為了和 K8S 對(duì)接,需要開發(fā) Flexvolume 或 CSI 驅(qū)動(dòng)。
磁盤配額
前文已經(jīng)介紹過(guò),K8S 目前支持基于 Project quotas 來(lái)統(tǒng)計(jì) Pod 的磁盤用量。這里簡(jiǎn)單總結(jié)一下 Linux 磁盤配額機(jī)制。
配額目標(biāo)
Linux 系統(tǒng)支持以下幾種角度的配額:
-
在文件系統(tǒng)級(jí)別,限制群組能夠使用的最大磁盤額度 -
在文件系統(tǒng)級(jí)別,限制單個(gè)用戶能夠使用的最大磁盤額度 -
限制某個(gè)目錄(directory, project)能夠占用的最大磁盤額度
前面 2 種配額,現(xiàn)代 Linux 都支持,不需要前提條件。你甚至可以在一個(gè)虛擬的文件系統(tǒng)上進(jìn)行配額:
# 寫一個(gè)空白文件
$ dd if=/dev/zero of=/path/to/the/file bs=4096 count=4096
# 格式化
...
# 掛載為虛擬文件系統(tǒng)
$ mount -o loop,rw,usrquota,grpquota /path/to/the/file /path/of/mount/point
# 進(jìn)行配額設(shè)置...
第 3 種需要較新的文件系統(tǒng),例如 XFS、ext4fs。
配額角度
配額可以針對(duì) Block 用量進(jìn)行,也可以針對(duì) inode 用量進(jìn)行。
配額可以具有軟限制、硬限制。超過(guò)軟限制后,仍然可以正常使用,但是登陸后會(huì)收到警告,在 grace time 倒計(jì)時(shí)完畢之前,用量低于軟限制后,一切恢復(fù)正常。如果 grace time 到期仍然沒(méi)做清理,則無(wú)法創(chuàng)建新文件。
統(tǒng)計(jì)用量
啟用配額,內(nèi)核自然需要統(tǒng)計(jì)用量。管理員要查詢用量,可以使用 xfs_quota 這樣的命令,比 du 這種遍歷文件計(jì)算的方式要快得多。
啟用配額
在保證底層文件系統(tǒng)支持之后,你需要修改掛載選項(xiàng)來(lái)啟用配額:
-
uquota/usrquota/quota:針對(duì)用戶設(shè)置配額 -
gquota/grpquota:針對(duì)群組設(shè)置配額 -
pquota/prjquota:針對(duì)目錄設(shè)置配額
LVM
使用 LVM 你可以任意創(chuàng)建具有尺寸限制的邏輯卷,把這些邏輯卷掛載給 Pod 即可:
volumes:
- flexVolume:
# 編寫的flexVolume驅(qū)動(dòng)放到
# /usr/libexec/kubernetes/kubelet-plugins/volume/exec/kubernetes.io~lvm/lvm
driver: kubernetes.io/lvm
fsType: ext4
options:
size: 30Gi
volumegroup: docker
name: mnt
volumeMounts:
- mountPath: /mnt
name: mnt
這需要修改編排方式,不使用 emptyDir 這種本地臨時(shí)存儲(chǔ),還需要處理好邏輯卷清理工作。
Flexvolume 驅(qū)動(dòng)的示例可以參考:/flexvolume-study-note#lvm[2]。
參考資料
-
https://blog.spider.im/post/control-disk-size-in-docker[3] -
https://ieevee.com/tech/2019/05/23/ephemeral-storage.html[4] -
https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/125.html[5] -
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage[6] -
https://coolshell.cn/articles/17200.html[7]
腳注
/kubernetes-study-note#out-of-resource: https://blog.gmem.cc/kubernetes-study-note#out-of-resource
[2]/flexvolume-study-note#lvm: https://blog.gmem.cc/flexvolume-study-note#lvm
[3]https://blog.spider.im/post/control-disk-size-in-docker: https://blog.spider.im/post/control-disk-size-in-docker/
[4]https://ieevee.com/tech/2019/05/23/ephemeral-storage.html: https://ieevee.com/tech/2019/05/23/ephemeral-storage.html
[5]https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/125.html: https://wizardforcel.gitbooks.io/vbird-linux-basic-4e/content/125.html
[6]https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage
[7]https://coolshell.cn/articles/17200.html: https://coolshell.cn/articles/17200.html
原文鏈接:https://blog.gmem.cc/limit-disk-usage-for-pods


你可能還喜歡
點(diǎn)擊下方圖片即可閱讀

云原生是一種信仰 ??
關(guān)注公眾號(hào)
后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!

點(diǎn)擊 "閱讀原文" 獲取更好的閱讀體驗(yàn)!
發(fā)現(xiàn)朋友圈變“安靜”了嗎?

