[TOC]
節點壓力驅逐是 kubelet 主動終止 Pod 以回收節點上資源的過程。kubelet 監控集群節點的 CPU、內存、磁盤空間和文件系統的 inode 等資源。 當這些資源中的一個或者多個達到特定的消耗水平, kubelet 可以主動地使節點上一個或者多個 Pod 失效,以回收資源防止資源不足。
kubelet中有幾個參數,通過這幾個參數可以為系統進程預留資源,不至于pod把計算資源耗盡,而導致系統操作都無法正常進行。
```shell
--enforce-node-allocatable
--system-reserved
--system-reserved-cgroup
--kube-reserved
--kube-reserved-cgroup
--eviction-hard
```
在kubernetes 1.6版本后,引入了Node的Allocatable特性,通過該特性我們可以控制每個節點可分配的資源。

Kubernetes 節點上的 'Allocatable' 被定義為 pod 可用計算資源量。 調度器不會超額申請 'Allocatable'。 目前支持 'CPU', 'memory' 和 'ephemeral-storage' 這幾個參數。
Capacity是指Node的容量,allocatable的值為 `allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold`
當kubelet啟動后,Node的allocatable就是固定的,不會因為pod的創建與銷毀而改變。
## allocatable、 requests 和 limits 三者關系
在pod的yaml文件中,我們可以為pod設置requests與limits。其中limits與allocatable沒有什么關系。但requests與allocatable關系緊密。調度到某個節點上的Pod的requests總和不能超過該節點的allocatable。limits的總和沒有上限。
比如某個節點的內存的allocatable為10Gi,有三個Pod(requests.memory=3Gi)已經調度到該節點上,那么第4個Pod就無法調度到該節點上,即使該Node上的空閑內存大于3Gi。
## 系統資源預留
系統資源預留分為兩種`不設cgroup` 和 `設置cgroup`。
- 不設cgroup:Pod使用的資源上限不會超過allocatable,如超過則被系統oom掉。系統使用資源超過kube-reserved和system-reserved閾值。可以使用allocatable的資源
- 設置cgroup:Pod使用的資源上限還是不會超過allocatable。但是系統使用資源超過kube-reserved和system-reserved閾值的話,會被cgroup殺掉。所以推薦使用第一種。
### 不設cgroup
假設我們現在需要為系統預留一定的資源,那么我們可以配置如下的kubelet參數(在這里不設置對應的cgroup參數):
```shell
--enforce-node-allocatable=pods
--kube-reserved=memory=...
--system-reserved=memory=...
--eviction-hard=...
```
1. 設置kubelet參數
這里的設置是將kubelet的配置寫在配置文件中,使用`--config` 的參數指定配置文件即可。上面的參數設置會在某個版本移除。官方推薦將配置寫在文件中
```yaml
enforceNodeAllocatable: ["pods"]
systemReserved:
cpu: 1000m
memory: 500Mi
kubeReserved:
cpu: 1000m
memory: 500Mi
evictionHard:
memory.available: 10%
imagefs.available: 10%
imagefs.inodesFree: 10%
nodefs.available: 10%
nodefs.inodesFree: 10%
```
2. 查看capacity及allocatable
查看到Node的capacity及allocatable的值如下:
```shell
$ kubectl describe node k8s-master01
...
Capacity:
cpu: 8
ephemeral-storage: 40940Mi
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 3861512Ki
pods: 100
Allocatable:
cpu: 6
ephemeral-storage: 36635831233
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 2510193454
pods: 100
```
以內存為例,可以計算出allocatable的值,剛好與上面的一致:
```shell
allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold
2510193454/1024Ki = 3861512Ki - 500*1024Ki - 500*1024Ki - 3861512*10%Ki
```
3. 查看kubepods控制組
查看kubepods控制組中對內存的限制,該值決定了Node上所有的Pod能使用的資源上限:
```shell
$ cat /sys/fs/cgroup/memory/kubepods.slice/memory.limit_in_bytes
2905612288
```
2905612288Bytes = 2837512Ki = Allocatable + 1000Mi
根據上面的計算可知,Node上Pod能實際使用的資源上限值為:
```shell
kubepods/memory.limit_in_bytes = capacity - kube_reserved - system_reserved
```
**注意:根據上面的公式,我們可以知道,一個節點上所有Pod能使用的內存總和,與eviction-hard無關**
### 設置cgroup
假設我們現在需要為系統預留一定的資源,那么我們可以配置如下的kubelet參數(在這里設置對應的cgroup參數):
```shell
--enforce-node-allocatable=pods,kube-reserved,system-reserved
--kube-reserved=memory=...
--kube-reserved-cgroup=...
--system-reserved=memory=...
--system-reserved-cgroup=...
--eviction-hard=..
```
如果還設置了對應的 --system-reserved-cgroup 和 --kube-reserved-cgroup參數,Pod能實際使用的資源上限不會改變(即kubepods.limit_in_bytes不變),但系統進程與kube進程也會受到資源上限的限制。如果系統進程超過了預留資源,那么系統進程會被cgroup殺掉。
但是如果不設這兩個參數,那么系統進程可以使用超過預留的資源上限。
## 配置建議
```shell
--enforce-node-allocatable=pods
--kube-reserved=cpu=xx,memory=xx,ephemeral-storage=xx
--system-reserved=cpu=xx,memory=xx,ephemeral-storage=xx
--eviction-hard=memory.available<10%,nodefs.available<10%
```
一般來說,我們不希望資源的使用率超過70%,所以kube-reserved、system-reserved、eviction-hard都應該設為10%。但由于kube-reserved與system-reserved不能設置百分比,所以它們要設置為絕對值。
## 總結
1. Node的allocatable在kubelet啟動后是一個固定的值,不會因為pod的創建與刪除而改變
2. 當我們為Pod設置了resources.requests時,調度到Node上的Pod的resources.requests的總和不會超過Node的allocatable。但Pod的resources.limits總和可以超過Node的allocatable
3. 一個Pod能否成功調度到某個Node,關鍵看該Pod的resources.request是否小于Node剩下的request,而不是看Node實際的資源空閑量。即使空閑資源小于Pod的requests,Pod也可以調度到該Node上
4. 當Pod的內存資源實際使用量超過其limits時,docker(實際是cgroup)會把該Pod內超出限額的進程殺掉(OOM);如果CPU超過,不會殺掉進程,只是進程會一直等待CPU。
5. allocatable與kubepods.limit的值不一樣,它們之間相差一個 eviction_hard
6. 當我們不設置cgroup時,可以達到為系統預留資源的效果,即Pod的資源實際使用量不會超過allocatable的值(因為kubepods控制組中memory.limit_in_bytes的值就為allocatable的值)。即使系統本身沒有使用完預留的那部分資源,Pod也無法使用。當系統超出了預留的那部分資源時,系統進程可以搶占allocatable中的資源,即對系統使用的資源沒有限制。
7. 當我們設置了cgroup參數,還設置了對應的cgroup時(如下),那么除了Pod使用的資源上限不會超過allocatable外,系統使用的資源上限也不會超過預留資源。當系統進程超過預留資源時,系統進程也會被cgroup殺掉。所以推薦使用上面的設置方法
## 參考
https://kubernetes.io/zh/docs/tasks/administer-cluster/out-of-resource/
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/node-pressure-eviction/
- 前言
- 架構
- 部署
- kubeadm部署
- kubeadm擴容節點
- 二進制安裝基礎組件
- 添加master節點
- 添加工作節點
- 選裝插件安裝
- Kubernetes使用
- k8s與dockerfile啟動參數
- hostPort與hostNetwork異同
- 應用上下線最佳實踐
- 進入容器命名空間
- 主機與pod之間拷貝
- events排序問題
- k8s會話保持
- 容器root特權
- CNI插件
- calico
- calicoctl安裝
- calico網絡通信
- calico更改pod地址范圍
- 新增節點網卡名不一致
- 修改calico模式
- calico數據存儲遷移
- 啟用 kubectl 來管理 Calico
- calico卸載
- cilium
- cilium架構
- cilium/hubble安裝
- cilium網絡路由
- IP地址管理(IPAM)
- Cilium替換KubeProxy
- NodePort運行DSR模式
- IP地址偽裝
- ingress使用
- nginx-ingress
- ingress安裝
- ingress高可用
- helm方式安裝
- 基本使用
- Rewrite配置
- tls安全路由
- ingress發布管理
- 代理k8s集群外的web應用
- ingress自定義日志
- ingress記錄真實IP地址
- 自定義參數
- traefik-ingress
- traefik名詞概念
- traefik安裝
- traefik初次使用
- traefik路由(IngressRoute)
- traefik中間件(middlewares)
- traefik記錄真實IP地址
- cert-manager
- 安裝教程
- 頒布者CA
- 創建證書
- 外部存儲
- 對接NFS
- 對接ceph-rbd
- 對接cephfs
- 監控平臺
- Prometheus
- Prometheus安裝
- grafana安裝
- Prometheus配置文件
- node_exporter安裝
- kube-state-metrics安裝
- Prometheus黑盒監控
- Prometheus告警
- grafana儀表盤設置
- 常用監控配置文件
- thanos
- Prometheus
- Sidecar組件
- Store Gateway組件
- Querier組件
- Compactor組件
- Prometheus監控項
- grafana
- Querier對接grafana
- alertmanager
- Prometheus對接alertmanager
- 日志中心
- filebeat安裝
- kafka安裝
- logstash安裝
- elasticsearch安裝
- elasticsearch索引生命周期管理
- kibana安裝
- event事件收集
- 資源預留
- 節點資源預留
- imagefs與nodefs驗證
- 資源預留 vs 驅逐 vs OOM
- scheduler調度原理
- Helm
- Helm安裝
- Helm基本使用
- 安全
- apiserver審計日志
- RBAC鑒權
- namespace資源限制
- 加密Secret數據
- 服務網格
- 備份恢復
- Velero安裝
- 備份與恢復
- 常用維護操作
- container runtime
- 拉取私有倉庫鏡像配置
- 拉取公網鏡像加速配置
- runtime網絡代理
- overlay2目錄占用過大
- 更改Docker的數據目錄
- Harbor
- 重置Harbor密碼
- 問題處理
- 關閉或開啟Harbor的認證
- 固定harbor的IP地址范圍
- ETCD
- ETCD擴縮容
- ETCD常用命令
- ETCD數據空間壓縮清理
- ingress
- ingress-nginx header配置
- kubernetes
- 驗證yaml合法性
- 切換KubeProxy模式
- 容器解析域名
- 刪除節點
- 修改鏡像倉庫
- 修改node名稱
- 升級k8s集群
- 切換容器運行時
- apiserver接口
- 其他
- 升級內核
- k8s組件性能分析
- ETCD
- calico
- calico健康檢查失敗
- Harbor
- harbor同步失敗
- Kubernetes
- 資源Terminating狀態
- 啟動容器報錯