基本
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
资源约束在我们平时使用的时候主要是cpu和内存层面, 以及本地临时存储(emptyDir)
k8s资源约束分为两种: request(软约束) 和 limits(硬约束)
k8s通过request(软约束)将Pod调度到有资源的Node上,确保了pod中的容器至少可以使用这么多资源. 不过当节点如果没有其它容器,则此容器可以突破request限制.
k8s通过limits(硬约束) 将调度完毕的Pod所使用的资源限制在limits之内。如果容器请求的内存大于了limits,则会收到oom错误。
如果只设置了limits,则k8s会将request的值自动设置为和limits一致。
写法
spec.containers[].resources.limits.cpu
cpu限制spec.containers[].resources.limits.memory
内存限制spec.containers[].resources.limits.hugepages-<size>
不常用, 可以忽略spec.containers[].resources.limits.ephemeral-storage
empty临时存储限制spec.containers[].resources.requests.cpu
spec.containers[].resources.requests.memory
spec.containers[].resources.requests.hugepages-<size>
不常用, 可以忽略spec.containers[].resources.requests.ephemeral-storage
单位
k8s将一个超线程称为一个vcpu. 1vcpu=1000m. 我们在定义资源限制时, 应该始终用 m 作为单位.假设你限制0.5个vcpu,则填写500m.
k8s的内存和临时存储单位和平时我们所用的没什么区别. 你只需要记住 K/M/G/T/P/E 这些即可. 例如, 100M就是100兆
一个例子:
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64M"
cpu: "250m"
ephemeral-storage: "2Gi"
limits:
memory: "128M"
cpu: "500m"
ephemeral-storage: "4Gi"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64M"
cpu: "250m"
ephemeral-storage: "2Gi"
limits:
memory: "128M"
cpu: "500m"
ephemeral-storage: "4Gi"
资源限制如何运作
k8s会通过kubelet将pod定义的资源限制传递给容器.
如果你容器使用的是docker.
cpu软限制将对标docker的–cpu-shares. 而cpu硬限制会告诉容器每100ms可以使用的CPU时间总量是 limits.cpu * 100.
关于docker的–cpu-shares, 可以参考https://docs.docker.com/engine/reference/run/#cpu-share-constraint
总的来说, --cpu-shares 会让容器按照所设定的分值比例去使用cpu.不过, 在多核心节点上, 这个规则又不是很适用. 按照官方的说法, 当多核心cpu的时候,它的规则是:
On a multi-core system, the shares of CPU time are distributed over all CPU cores. Even if a container is limited to less than 100% of CPU time, it can use 100% of each individual CPU core.
For example, consider a system with more than three cores. If you start one container
{C0}
with-c=512
running one process, and another container{C1}
with-c=1024
running two processes, this can result in the following division of CPU shares:PID container CPU CPU share 100 {C0} 0 100% of CPU0 101 {C1} 1 100% of CPU1 102 {C1} 2 100% of CPU2
这里三个容器,都是单核心程序
内存的限制没有什么特别需要注意的.
容器中的可见资源
默认情况下,不管你如何设置资源限制,容器里的可见资源都等于节点资源.也就是说你在容器里查看/proc/meminfo显示的资源并不是你设置的.这个问题会带来很多麻烦.
因为很多程序的参数都是根据可见资源来设定的.例如nginx的auto, 或者jvm里的内存参数.
从 Java 8u191开始, jvm 已经默认实现了容器感知( -XX:+UseContainerSupport). 因此无需安装下面的 lxcfs 方案.
并且, 在容器中建议只设置如下内存参数:
-XX:MaxRAMPercentage 最大堆内存=物理内存百分比, 建议为容器限制的50%-75% . 毕竟还需要预留其它内存.
而社区常见的作法是用lxcfs
来提升资源的可见性.lxcfs
是一个开源的FUSE(用户态文件系统)实现来支持LXC容器, 它也可以支持Docker容器.
LXCFS通过用户态文件系统, 在容器中提供下列 procfs
的文件.
/proc/cpuinfo
/proc/diskstats
/proc/meminfo
/proc/stat
/proc/swaps
/proc/uptime
与我们资源限制有关的, 主要是 cpuinfo 和 meminfo.
目前社区的做法如下:
-
所有节点安装 fuse-libs 包.
yum install -y fuse-libs
-
安装部署lxcfs
git clone https://github.com/denverdino/lxcfs-admission-webhook.git cd lxcfs-admission-webhook vim deployment/lxcfs-daemonset.yaml === 修正配置里的 apiVersion === 当前git里的代码是陈旧的...代码里的版本在 1.18 已经被废弃). 具体归属于什么版本, 请参考k8s官方api文档 === https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#daemonset-v1-apps apiVersion:apps/v1 kubectl apply -f deployment/lxcfs-daemonset.yaml kubectl get pod #等待 lxcfs pod 状态成 running #如果你发现 pod 始终出错,那么执行下列命令: kubectl delete -f deployment/lxcfs-daemonset.yaml rm -rf /var/lib/lxcfs kubectl apply -f deployment/lxcfs-daemonset.yaml deployment/install.sh kubectl get secrets,pods,svc,mutatingwebhookconfigurations === 查看各个对象状态
-
给相关namespace注入lxcfs,例如default
kubectl label namespace default lxcfs-admission-webhook=enabled
-
重启添加了资源限制的pod, 此时 /proc/cpuinfo 和 /proc/meminfo 将会正确显示.