> For the complete documentation index, see [llms.txt](https://pshizhsysu.gitbook.io/kubernetes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pshizhsysu.gitbook.io/kubernetes/zi-yuan-guan-kong.md).

# 资源预留

kubelet中有几个参数，通过这几个参数可以为系统进程预留资源，不至于pod把计算资源耗尽，而导致系统操作都无法正常进行。

```
--enforce-node-allocatable
--system-reserved
--system-reserved-cgroup
--kube-reserved
--kube-reserved-cgroup
--eviction-hard
```

## Allocatable

在kubernetes 1.6版本后，引入了Node的Allocatable特性，通过该特性我们可以控制每个节点可分配的资源。

借用官网的图如下：

```
       capacity
------------------------
|     kube-reserved    |
------------------------
|     system-reserved  |
------------------------
|     eviction-threshhold    |
------------------------
|     allocatable      |
| (available for pods) |
----------------------
```

Capacity是指Node的容量，allocatable的值为

```
allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold
```

当kubelet启动后，Node的allocatable就是固定的，不会因为pod的创建与销毁而改变。

* allocatable vs requests vs 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

假设我们现在需要为系统预留一定的资源，那么我们可以配置如下的kubelet参数（在这里我们不设置对应的cgroup参数）：

```
--enforce-node-allocatable=pods
--kube-reserved=memory=...
--system-reserved=memory=...
--eviction-hard=...
```

在上面提到，节点上Pod的requests总和不能超过allocatable。

**当我们设置了以上的四个参数时，节点上所有Pod实际使用的资源总和不会超过capacity - kube\_reserved - system\_reserved**

我们可以通过实验进行验证。

1、参数设置

kubelet的启动参数如下：

> /usr/bin/kubelet --address=0.0.0.0 --allow-privileged=true --cluster-dns=10.254.0.10 --cluster-domain=kube.local --fail-swap-on=true --hostname-override=192.168.1.101 --kubeconfig=/etc/kubernetes/kubeconfig --pod-infra-container-image=10.142.232.115:8021/library/pause:latest --port=10250 --enforce-node-allocatable=pods --kube-reserved=memory=1Gi --system-reserved=memory=1Gi --cgroup-driver=cgroupfs --eviction-hard=memory.available<100Mi

2、查看capacity及allocatable

查看到Node的capacity及allocatable的值如下：

```
Capacity:
 cpu:     2
 memory:  4016436Ki (约3.83Gi)
 pods:    110
Allocatable:
 cpu:     2
 memory:  1816884Ki (约1.73Gi)
 pods:    110
```

我们可以计算出allocatable的值，刚好与上面的一致：

```
allocatale = capacity - kube_reserved - system_reserved - eviction_hard
1816884Ki = 4016436Ki - 1*1024*1024Ki - 1*1024*1024Ki - 100*1024Ki
```

我们可以通过free命令来查看Node的total值，与capacity一致：

```
$ free -k
              total        used        free      shared  buff/cache   available
Mem:        4016436     1224372     2234872       17100      557192     2453156
Swap:             0           0           0
```

3、查看kubepods控制组

查看kubepods控制组中对内存的限制，该值决定了Node上所有的Pod能使用的资源上限：

```
$ cat /sys/fs/cgroup/memory/kubepods/memory.limit_in_bytes 
1965346816
```

1965346816 Bytes = 1919284Ki = allocatable + 100Mi

根据上面的计算可知，Node上Pod能实际使用的资源上限值为：

```
kubepods/memory.limit_in_bytes = capacity - kube_reserved - system_reserved
```

**注意：根据上面的公式，我们可以知道，一个节点上所有Pod能使用的内存总和，与eviction-hard无关**

4、查看内存的空闲情况

查看内存的使用情况，发现空闲内存为 2.3Gi

```
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           3.8G        1.2G        2.1G         16M        544M        2.3G
Swap:            0B          0B          0B
```

5、创建pod

此时内存的空闲值为2.3Gi，allocatable为1.73Gi，kubepod.limit为1.83Gi。

我们创建一个Pod，pod.request为0.1Gi，pod.limit为20Gi，Pod实际消耗内存1Gi。理论上该Pod能创建成功，实际也成功了，如下：

备注：yaml文件消耗内存的脚本见本文附录

```
$ kubectl get pod
NAME                      READY     STATUS    RESTARTS   AGE
centos-659755bf78-jdlrc   1/1       Running   0          44s
```

查看Node的内存使用情况：

```
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           3.8G        2.2G        1.1G         16M        546M        1.3G
Swap:            0B          0B          0B
```

此时，空闲内存为1.3Gi，Node剩余的request为1.63Gi，Node的kubepods.limit还剩0.83Gi。

我们再创建一个同样的Pod，根据推测，Pod可以调度成功，但是由于要消耗1Gi的实际内存，超过了0.83Gi，那么该Pod会出现OOM。实验结果也的确如此：

```
$ kubectl get pod
NAME                      READY     STATUS      RESTARTS   AGE
centos-659755bf78-j8wjv   0/1       OOMKilled   0          5s
centos-659755bf78-jdlrc   1/1       Running     1          1m
```

## 资源预留 - 设置对应的cgroup

如果还设置了对应的 `--system-reserved-cgroup` 和 `--kube-reserved-cgroup`参数，Pod能实际使用的资源上限不会改变（即kubepods.limit\_in\_bytes不变），但系统进程与kube进程也会受到资源上限的限制。如果系统进程超过了预留资源，那么系统进程会被cgroup杀掉。

但是如果不设这两个参数，那么系统进程可以使用超过预留的资源上限。

## 配置建议

为kubelet设置以下四个参数即可：

```
--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不能设置百分比，所以它们要设置为绝对值。

## 总结

* Node的allocatable在kubelet启动后是一个固定的值，不会因为pod的创建与删除而改变
* 当我们为Pod设置了resources.requests时，调度到Node上的Pod的resources.requests的总和不会超过Node的allocatable。但Pod的resources.limits总和可以超过Node的allocatable
* 一个Pod能否成功调度到某个Node，关键看该Pod的resources.request是否小于Node剩下的request，而不是看Node实际的资源空闲量。即使空闲资源小于Pod的requests，Pod也可以调度到该Node上
* 当Pod的资源实际使用量超过其limits时，docker（实际是cgroup）会把该Pod内超出限额的进程杀掉
* 当我们只设置如下四个参数时，可以达到为系统预留资源的效果，即Pod的资源实际使用量不会超过allocatable的值（因为`kubepods`控制组中memory.limit\_in\_bytes的值就为allocatable的值）。即使系统本身没有使用完预留的那部分资源，Pod也无法使用。当系统超出了预留的那部分资源时，系统进程可以抢占allocatable中的资源，即对系统使用的资源没有限制。

```
--enforce-node-allocatable=pods
--kube-reserved=memory=...
--system-reserved=memory=...
--eviction-hard=...
```

* 当我们除了设置了以上四个参数，还设置了对应的cgroup时（如下），那么除了Pod使用的资源上限不会超过allocatable外，系统使用的资源上限也不会超过预留资源。当系统进程超过预留资源时，系统进程也会被cgroup杀掉。所以推荐使用上面的设置方法

```
--enforce-node-allocatable=pods,kube-reserved,system-reserved
--kube-reserved=memory=...
--kube-reserved-cgroup=...
--system-reserved=memory=...
--system-reserved-cgroup=...
--eviction-hard=...
```

* allocatable与kubepods.limit的值不一样，它们之间相差一个 eviction\_hard

```
allocatable = capacity - kube_reserved - system_reserved - eviction_hard
kubepods.limit = capacity - kube_reserved - system_reserved
```

## 附录

* centos.yaml

```
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: centos
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      name: centos
  template:
    metadata:
      labels:
        name: centos
    spec:
      volumes:
      - name: volume1
        hostPath:
          path: /home/docker/yaml/mem.py
      containers:
      - name: centos
        image: 10.142.232.115:8021/library/centos:centos7
        command:
        - python
        - /mem.py
        - 1GB
        volumeMounts:
        - mountPath: /mem.py
          name: volume1
        resources:
          requests:
            memory: 0.1Gi
          limits:
            memory: 20Gi
```

* mem.py

```
import sys
import re
import time

def print_help():
    print 'Usage: '
    print '  python mem.py 100MB'
    print '  python mem.py 1GB'

if __name__ == "__main__":
    if len(sys.argv) == 2:
        pattern = re.compile('^(\d*)([M|G]B)$')
        match = pattern.match(sys.argv[1].upper())
        if match:
            num = int(match.group(1))
            unit = match.group(2)
            if unit == 'MB':
                s = ' ' * (num * 1024 * 1024)
            else:
                s = ' ' * (num * 1024 * 1024 * 1024)

            time.sleep(10000)
        else:
            print_help()
    else:
        print_help()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pshizhsysu.gitbook.io/kubernetes/zi-yuan-guan-kong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
