所有容器都应该设置Requests
requests 的值并不是指给容器实际分配的资源大小,它仅仅是给调度器看的,调度器会 "观察" 每个节点可以用于分配的资源有多少,也知道每个节点已经被分配了多少资源。被分配资源的大小就是节点上所有 Pod 中定义的容器 requests 之和,它可以计算出节点剩余多少资源可以被分配(可分配资源减去已分配的 requests 之和)。如果发现节点剩余可分配资源大小比当前要被调度的 Pod 的 reuqests 还小,那么就不会考虑调度到这个节点,反之,才可能调度。所以,如果不配置requests,那么调度器就不能知道节点大概被分配了多少资源出去,调度器得不到准确信息,也就无法做出合理的调度决策,很容易造成调度不合理,有些节点可能很闲,而有些节点可能很忙,甚至 NotReady。
所以,建议是给所有容器都设置 requests,让调度器感知节点有多少资源被分配了,以便做出合理的调度决策,让集群节点的资源能够被合理的分配使用,避免陷入资源分配不均导致一些意外发生。
CPU requests与limits的一般性建议
• 如果不确定应用最佳的 CPU 限制,可以不设置 CPU limit,参考: Understanding resource limits in kubernetes: cpu time。
• 如果要设置 CPU requests,大多可以设置到不大于 1 核,除非是 CPU 密集型应用。
为什么 CPU 利用率远不到 limit 还会被 throttle ?
CPU 限流是因为内核使用 CFS 调度算法,对于微突发场景,在一个 CPU 调度周期内 (100ms) 所占用的时间超过了 limit 还没执行完,就会强制 "抢走" CPU 使用权(throttle),等待下一个周期再执行,但是时间拉长一点,进程使用 CPU 所占用的时间比例却很低,监控上就看不出来 CPU 有突增,但实际上又被 throttle 了。
怎样设置才能提高资源利用率?
如果给你的应用设置较高的 requests 值,而实际占用资源长期远小于它的 requests 值,导致节点整体的资源利用率较低。当然这对时延非常敏感的业务除外,因为敏感的业务本身不期望节点利用率过高,影响网络包收发速度。所以对一些非核心,并且资源不长期占用的应用,可以适当减少 requests 以提高资源利用率。
如果你的服务支持水平扩容,单副本的 requests 值一般可以设置到不大于 1 核,CPU 密集型应用除外。比如 coredns,设置到 0.1 核就可以,即 100m。
尽量避免使用过大的 requests 与 limit
如果你的服务使用单副本或者少量副本,给很大的 requests 与 limit,让它分配到足够多的资源来支撑业务,那么某个副本故障对业务带来的影响可能就比较大,并且由于 requests 较大,当集群内资源分配比较碎片化,如果这个 Pod 所在节点挂了,其它节点又没有一个有足够的剩余可分配资源能够满足这个 Pod 的 requests 时,这个 Pod 就无法实现漂移,也就不能自愈,加重对业务的影响。
相反,建议尽量减小 requests 与 limit,通过增加副本的方式来对你的服务支撑能力进行水平扩容,让你的系统更加灵活可靠。
老是忘记设置怎么办?
可以对一个namespace下的所有pod设置限制的默认值————LimitRange
LimitRange不会影响已经创建的资源
# 配置默认的requests和limits
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-mem-limit-range
spec:
limits:
- default:
cpu: 1
memory: 512Mi
defaultRequest:
cpu: 0.5
memory: 256Mi
type: Container
# 创建pod
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo
spec:
containers:
- name: default-cpu-demo-ctr
image: nginx
# 查看此pod的配置
k get pod default-cpu-demo -o yaml
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo
namespace: default
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: default-cpu-demo-ctr
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: 500m
memory: 256Mi
如果配置了limits而没有配置requests,那么requests默认值就会被设置为limits配置的参数。
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-mem-limit-range
spec:
limits:
- default:
cpu: 1
memory: 512Mi
type: Container
# 查看此pod的配置
k get pod default-cpu-demo -o yaml
apiVersion: v1
kind: Pod
metadata:
name: default-cpu-demo
namespace: default
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: default-cpu-demo-ctr
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: "1"
memory: 512Mi# 配置requests和limits的范围
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-min-max-demo-lr
spec:
limits:
- max:
cpu: "800m"
memory: 1Gi
min:
cpu: "200m"
memory: 500Mi
type: Container
# 会自动添加一个默认配置
k get limitrange cpu-min-max-demo-lr -o yaml
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-min-max-demo-lr
namespace: default
spec:
limits:
- default:
cpu: 800m
memory: 1Gi
defaultRequest:
cpu: 800m
memory: 1Gi
max:
cpu: 800m
memory: 1Gi
min:
cpu: 200m
memory: 500Mi
type: Container# 限制申请存储空间的大小
apiVersion: v1
kind: LimitRange
metadata:
name: storagelimits
spec:
limits:
- max:
storage: 2Gi
min:
storage: 1Gi
type: PersistentVolumeClaim
避免测试 namespace 消耗过多资源影响生产业务
若生产集群有用于测试的 namespace,如果不加以限制,可能导致集群负载过高,从而影响生产业务。可以使用 ResourceQuota 来限制测试 namespace 的 requests 与 limit 的总大小。
对一个namespace设置限制——ResourceQuota
namespace在创建了ResourceQuota后才会启用资源使用的配额,没有创建ResourceQuota的Namespace不限制资源使用。
# 定义
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-test
labels:
app: resourcequota
spec:
hard:
pods: 50
requests.cpu: 0.5
requests.memory: 512Mi
limits.cpu: 5
limits.memory: 16Gi
configmaps: 20
requests.storage: 40Gi
persistentvolumeclaims: 20
replicationcontrollers: 20
secrets: 20
services: 50
services.loadbalancers: "2"
services.nodeports: "10"
# 查看详情
k get quota
NAME AGE REQUEST LIMIT
resource-test 12m configmaps: 1/20, persistentvolumeclaims: 2/20, pods: 1/50, replicationcontrollers: 0/20, requests.cpu: 0/500m, requests.memory: 0/512Mi, requests.storage: 200Mi/40Gi, secrets: 0/20, services: 5/50, services.loadbalancers: 0/2, services.nodeports: 1/10 limits.cpu: 0/5, limits.memory: 0/16Gi
# 创建测试ns
k create ns quota-example
# 使用
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota-demo
namespace: quota-example
spec:
hard:
persistentvolumeclaims: 1
# 查看详情
k get quota object-quota-demo -n quota-example -o yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota-demo
namespace: quota-example
spec:
hard:
persistentvolumeclaims: "1"
status:
hard:
persistentvolumeclaims: "1"
used:
persistentvolumeclaims: "0" # 可用1
# 创建一个pvc:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-quota-demo
namespace: quota-example
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
# 当前资源使用情况
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-quota-demo
namespace: quota-example
spec:
hard:
persistentvolumeclaims: "1"
status:
hard:
persistentvolumeclaims: "1"
used:
persistentvolumeclaims: "1" # 当前使用量为1,配额为1,再次创建会报错
QoS(Quality of Service服务质量)
内存和磁盘属于不可压缩的资源,当内存达到最高峰时会引起OOMKilled故障。
3种级别的服务质量,按优先级排序:
- Guaranteed最高服务质量,limits的cpu和memory等于requests的cpu和memory
- Burstable limits的cpu和memory大于requests的cpu和memory
- BestEffort 尽力而为,不设置limits和requests
重要的线上应用应该怎么配置
节点资源不足时,会触发自动驱逐,将一些低优先级的 Pod 删除掉以释放资源让节点自愈。没有设置 requests,limit 的 Pod 优先级最低,容易被驱逐;requests 不等于 limit 的其次; requests 等于 limit 的 Pod 优先级较高,不容易被驱逐。所以如果是重要的线上应用,不希望在节点故障时被驱逐导致线上业务受影响,就建议将 requests 和 limit 设成一致。即QoS中的Guaranteed。
# Guaranteed
pod中的每个容器都必须指定limits.memory=requests.memory,limits.cpu=limits.memory。
如果配置了limits而没有配置requests,那么requests默认值就会被设置为limits配置的参数。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- image: nginx
name: qos-demo
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
k get pod qos-demo -n qos-example -o yaml
status:
qosClass: Guaranteed
# Burstable
1.Pod不符合Guaranteed的配置要求
2.Pod中至少有1个容器配置了requests.cpu或requests.memory
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- image: nginx
name: qos-demo
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
k get pod qos-demo-2 -n qos-example -o yaml
status:
qosClass: Burstable
# besteffort
容器没有设置limits和requests即可
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- image: nginx
name: qos-demo
k get pod qos-demo-3 -n qos-example -o yaml
status:
qosClass: BestEffort
总结
通常情况,底层依赖的中间件的QoS会配置为Guaranteed,其他服务可能不需要太那么高的Qos。实际使用中,最有可能超额分配的是内存,而CPU通常使用率不高,只有在高频工作时,CPU才会处于忙碌状态。所以在设置resources参数时,内存的requests需要按需分配,对于CPU,Limits参数很重要,防止因为Pod的CPU过高,引起宿主机的问题。
应用健壮性要从哪些点去考虑?
- 应用的健康检查
- 平滑退出
- 亲和力
- Qos
- ResourceQuota