Pod 如何使用磁盤
容器在運行期間會產生臨時文件、日誌。如果沒有任何配額機制,則某些容器可能很快將磁盤寫滿,影響宿主機內核和所有應用。
容器的臨時存儲,例如 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掛載到這個掛載點
├── kubernetes.io~csi # CSI卷
└── kubernetes.io~secret # Secret類型的卷
└── default-token-jp4n8
├── ca.crt -> ..data/ca.crt
├── namespace -> ..data/namespace
└── token -> ..data/token
持久卷的掛載點也位於/var/lib/kubelet/pods 下,但是不會導致存儲空間的消耗。
容器的日誌,存放在/var/log/pods 目錄下。
使用 Docker 時,容器的 rootfs位於/var/lib/docker 下,具體位置取決於存儲驅動。
Pod 驅逐機制
磁盤容量不足觸發的驅逐
具體細節參考:/kubernetes-study-note#out-of-resource[1]。
當不可壓縮資源(內存、磁盤)不足時,節點上的 Kubelet 會嘗試驅逐掉某些 Pod,以釋放資源,防止整個系統受到影響。
其中,磁盤資源不足的信號來源有兩個:
-
imagefs:容器運行時用作存儲鏡像、可寫層的文件系統 -
nodefs:Kubelet 用作卷、守護進程日誌的文件系統
當 imagefs 用量到達驅逐閾值,Kubelet 會刪除所有未使用的鏡像,釋放空間。
當 nodefs 用量到達閾值,Kubelet 會選擇性的驅逐 Pod(及其容器)來釋放空間。
本地臨時存儲觸發的驅逐
較新版本的 K8S 支持設置每個 Pod 可以使用的臨時存儲的 request/limit,驅逐行爲可以更具有針對性。
如果 Pod 使用了超過限制的本地臨時存儲,Kubelet 將設置驅逐信號,觸發 Pod 驅逐流程:
-
對於容器級別的隔離,如果一個容器的可寫層、日誌佔用磁盤超過限制,則 Kubelet 標記 Pod 爲待驅逐 -
對於 Pod 級別的隔離,Pod 總用量限制,是每個容器限制之和。如果各容器用量之和+Pod 的 emptyDir 卷超過 Pod 總用量限制,標記 Pod 爲待驅逐
從編排層限制
從 K8S 1.8 開始,支持本地臨時存儲(local ephemeral storage),ephemeral 的意思是,數據的持久性(durability)不做保證。臨時存儲可能 Backed by 本地 Attach 的可寫設備,或者內存。
Pod 可以使用本地臨時存儲來作爲暫存空間,或者存放緩存、日誌。Kubelet 可以利用本地臨時存儲,將 emptyDir 卷掛載給容器。Kubelet 也使用本地臨時存儲來保存節點級別的容器日誌、容器鏡像、容器的可寫層。
Kubelet 會將日誌寫入到你配置好的日誌目錄,默認 /var/log
。其它文件默認都寫入到 /var/lib/kubelet
。在典型情況下,這兩個目錄可能都位於宿主機的 rootfs 之下。
Kubernetes 支持跟蹤、保留/限制 Pod 能夠使用的本地臨時存儲的總量。
限制 Pod 用量
打開特性開關:LocalStorageCapacityIsolation
,可以限制每個 Pod 能夠使用的臨時存儲的總量。
注意:以內存爲媒介(tmpfs)的 emptyDir,其用量計入容器內存消耗,而非本地臨時存儲消耗。
使用類似限制內存、CPU 用量的方式,限制本地臨時存儲用量:
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)。
下面這個例子,Pod 具有兩個容器,每個容器最多使用 4GiB 的本地臨時存儲:
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"
對 Pod 用量的監控
不監控
如果禁用 Kubelet 對本地臨時存儲的監控,則 Pod 超過 limit 限制後不會被驅逐。但是,如果磁盤整體上容量太低,節點會被打上污點,所有不能容忍此污點的 Pod 都會被驅逐。
週期性掃描
Kubelet 可以執行週期性的掃描,檢查 emptyDir 卷、容器日誌目錄、可寫容器層,然後計算 Pod/容器使用了多少磁盤。
這個模式下有個問題需要注意,Kubelet不會跟蹤已刪除文件的描述符。也就是說,如果你創建一個文件,打開文件,寫入 1GB,然後刪除文件,這種情況下 inode 仍然存在(直到你關閉文件),空間仍然被佔用,但是 Kubelet 卻沒有算這 1GB.
Project Quotas
此特性在 1.15+處於 Alpha 狀態。
Project quotas 是 Linux 操作系統級別的特性,用於在目錄級別限制磁盤用量。只有本地臨時存儲(例如 emptyDir)的後備(Backing)文件系統支持 Project quotas,纔可以使用該特性。XFS、ext4 都支持 Project quotas。
K8S 將佔用從 1048576 開始的 Project ID,佔用中的 ID 註冊在/etc/projects、/etc/projid 文件中。如果系統中其它進程佔用 Project ID,則也必須在這兩個文件中註冊,這樣 K8S 纔會改用其它 ID。
Quotas 比周期性掃描快,而且更加精準。當一個目錄被分配到一個 Project 中後,該目錄中創建的任何文件,都是在 Project 中創建的。爲了統計用量,內核只需要跟蹤 Project 中創建了多少 block 就可以了。
如果文件被創建、然後刪除,但是它的文件描述符仍然處於打開狀態,這種情況下,它仍然消耗空間,不會出現週期性掃描的那種漏統計的問題。
要啓用 Project Quotas,你需要:
-
開啓 Kubelet 特性開關:
LocalStorageCapacityIsolationFSQuotaMonitoring
-
確保文件系統支持 Project quotas:
-
XFS 文件系統默認支持,不需要操作
-
ext4 文件系統,你需要在未掛載之前,啓用:
$ sudo tune2fs -O project -Q prjquota /dev/vda
-
確保文件系統掛載時,啓用了 Project quotas。使用掛載選項
prjquota
inode 耗盡問題
有的時候,我們會發現磁盤寫入時會報磁盤滿
,但是 df
查看容量並沒有 100%使用,此時可能只是因爲 inode 耗盡造成的。
當前 k8s 並不支持對 Pod 的臨時存儲設置 inode 的 limits/requests。
但是,如果 node 進入了 inode 緊缺的狀態,kubelet 會將 node 設置爲 under pressure,不再接收新的 Pod 請求。
從容器引擎限制
Docker 提供了配置項 --storage-opt,可以限制容器佔用磁盤空間的大小,此大小影響鏡像和容器文件系統,默認 10G。
你也可以在 /etc/docker/daemon.json
中修改此配置項:
{
"storage-driver": "devicemapper",
"storage-opts": [
// devicemapper
"dm.basesize=20G",
// overlay2
"overlay2.size=20G",
]
}
但是這種配置無法影響那些掛載的卷,例如 emptyDir。
從系統層限制
你可以使用 Linux 系統提供的任何能夠限制磁盤用量的機制,爲了和 K8S 對接,需要開發 Flexvolume 或 CSI 驅動。
磁盤配額
前文已經介紹過,K8S 目前支持基於 Project quotas 來統計 Pod 的磁盤用量。這裏簡單總結一下 Linux 磁盤配額機制。
配額目標
Linux 系統支持以下幾種角度的配額:
-
在文件系統級別,限制羣組能夠使用的最大磁盤額度 -
在文件系統級別,限制單個用戶能夠使用的最大磁盤額度 -
限制某個目錄(directory, project)能夠佔用的最大磁盤額度
前面 2 種配額,現代 Linux 都支持,不需要前提條件。你甚至可以在一個虛擬的文件系統上進行配額:
# 寫一個空白文件
$ dd if=/dev/zero of=/path/to/the/file bs=4096 count=4096
# 格式化
...
# 掛載爲虛擬文件系統
$ mount -o loop,rw,usrquota,grpquota /path/to/the/file /path/of/mount/point
# 進行配額設置...
第 3 種需要較新的文件系統,例如 XFS、ext4fs。
配額角度
配額可以針對 Block 用量進行,也可以針對 inode 用量進行。
配額可以具有軟限制、硬限制。超過軟限制後,仍然可以正常使用,但是登陸後會收到警告,在 grace time 倒計時完畢之前,用量低於軟限制後,一切恢復正常。如果 grace time 到期仍然沒做清理,則無法創建新文件。
統計用量
啓用配額,內核自然需要統計用量。管理員要查詢用量,可以使用 xfs_quota 這樣的命令,比 du 這種遍歷文件計算的方式要快得多。
啓用配額
在保證底層文件系統支持之後,你需要修改掛載選項來啓用配額:
-
uquota/usrquota/quota:針對用戶設置配額 -
gquota/grpquota:針對羣組設置配額 -
pquota/prjquota:針對目錄設置配額
LVM
使用 LVM 你可以任意創建具有尺寸限制的邏輯卷,把這些邏輯卷掛載給 Pod 即可:
volumes:
- flexVolume:
# 編寫的flexVolume驅動放到
# /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 這種本地臨時存儲,還需要處理好邏輯卷清理工作。
Flexvolume 驅動的示例可以參考:/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
你可能還喜歡
點擊下方圖片即可閱讀
雲原生是一種信仰 🤘
關注公衆號
後臺回覆◉k8s◉獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!
點擊 "閱讀原文" 獲取更好的閱讀體驗!
發現朋友圈變“安靜”了嗎?
本文分享自微信公衆號 - 雲原生實驗室(cloud_native_yang)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。