Kubernetes Metric Server, Quota and Limits

Kubernetes Metric Server

环境准备

bash 复制代码
[root@master30 ~ 16:52:12]# kubectl create namespace metric
[root@master30 ~ 16:52:51]# kubectl config set-context --current --namespace metric

Metrics-Server 概述

我们在使用 Kubernetes 中过程中面临的问题:

  • 如何监控 node 计算资源使用情况?
  • 如何监控 pod 计算资源使用情况?
  • 如何根据 pod 计算资源使用情况,自动扩展?

我们可以使用 Metrics-Server监控:

  1. node 和 pod 计算资源使用情况。
  2. Metrics Server 是 Kubernetes 内置自动缩放管道的可扩展、高效的容器资源指标来源。
  3. Metrics Server 通过 Kubelet 收集资源指标,并通过 Metrics API 将它们公开在 Kubernetes apiserver 中,供 Horizontal Pod Autoscaler 和 Vertical Pod Autoscaler 使用。
  4. Metrics API 还可以通过 kubectl top 访问,从而更轻松地调试自动缩放管道。

Metrics Server 不适用于非自动缩放目的。 请勿将其用于将指标转发到监控解决方案,或作为监控解决方案指标的来源。 在这种情况下,请直接从 Kubelet /metrics/resource 端点收集指标。

指标服务器提供:

  • 适用于大多数集群的单一部署(请参阅要求)。
  • 快速自动缩放,每 15 秒收集一次指标。
  • 资源效率,集群中每个节点使用 1 mili 核心 CPU 和 2 MB 内存。
  • 可扩展支持多达 5,000 个节点集群。

Metrics-Server 部署

bash 复制代码
# 下载 Metrics-Server
root@master30:~# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.1/components.yaml

# 修改 Metrics-Server,不校验tls
[root@master30 ~ 16:57:52]# sed -i '/metric-resolution/a\        - --kubelet-insecure-tls' components-v0.7.1.yaml

# 更换镜像
[root@master30 ~ 16:58:21]# grep image: components-v0.7.1.yaml 
        image: registry.k8s.io/metrics-server/metrics-server:v0.7.1
[root@master30 ~ 16:58:50]# sed -i 's/registry.k8s.io/hub.laoma.cloud/g' components-v0.7.1.yaml

# 部署 Metrics-Server
[root@master30 ~ 16:59:04]# kubectl apply -f components-v0.7.1.yaml 
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
# 查看 Metrics-Server 状态
[root@master30 ~ 16:59:51]# kubectl get pod -n kube-system | grep metrics
metrics-server-5b98f887f4-5cdt6            1/1     Running   0               43s

Metrics-Server 使用

查看node状态

bash 复制代码
[root@master30 ~ 17:00:34]# kubectl top node
NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master30   124m         6%     1809Mi          48%       
worker31   40m          2%     1139Mi          30%       
worker32   56m          2%     993Mi           26% 

查看 pod 状态

bash 复制代码
[root@master30 ~ 17:00:52]# kubectl top pod -n kube-system 
NAME                                       CPU(cores)   MEMORY(bytes)   
calico-kube-controllers-585df69d45-khx5q   4m           78Mi            
calico-node-gcz8k                          21m          176Mi           
calico-node-j79pn                          22m          174Mi           
calico-node-sgw6l                          20m          175Mi           
coredns-7db6d8ff4d-8cs5g                   1m           41Mi            
coredns-7db6d8ff4d-rgsxf                   1m           31Mi            
etcd-master30                              16m          99Mi            
kube-apiserver-master30                    33m          353Mi           
kube-controller-manager-master30           8m           128Mi           
kube-proxy-jzjl5                           10m          71Mi            
kube-proxy-m6g6m                           7m           71Mi            
kube-proxy-q96th                           5m           72Mi            
kube-scheduler-master30                    2m           66Mi            
metrics-server-5b98f887f4-5cdt6            2m           15Mi  

单位:1cpu=1000m

扩容和减容控制

扩容和缩容时间参数

1. 指标采样周期
  • --horizontal-pod-autoscaler-sync-period duration
  • 默认:15s,HPA 每 15 秒拉取一次 metrics-server 指标。
2. 启动就绪窗口期
  • --horizontal-pod-autoscaler-initial-readiness-delay duration
  • 默认:30s,Pod 刚启动前 30 秒,视为 "启动中",不参与 HPA 计算
3. 缩容稳定窗口期
  • --horizontal-pod-autoscaler-downscale-stabilization duration
  • 默认:5m0s(5 分钟),缩容冷却时间。

持续高负载 → 扩容

  1. 15s 采集一次 CPU/内存指标
  2. Pod 刚启动前 30 秒,视为 "启动中",不参与 HPA 计算。
  3. 一次扩容动作完成后,再次等待 45s 冷却 才能下一次扩容

👉 结论:K8s 1.30 扩容最小间隔 = 45s

持续低负载 → 缩容

  1. 同样 15s 采样
  2. 指标长期低于阈值
  3. 需要满足 300s(5分钟)稳定低位 才会触发缩容
  4. 每次缩容后,再次锁定 5 分钟

设置扩容和减容时间参数

扩容和减容pod数量由kube-controller-manager管理,如需调快/调慢,直接修改 controller-manager 启动参数即可。

扩容和缩容pod是有冷却时间的,目的是防止流量抖动、瞬间峰值导致频繁炸裂扩容。

为了演示扩容和缩容效果,这里设置扩容冷却时间为30s(10+20),缩容冷却时间为60秒。

bash 复制代码
root@master30:~# vim /etc/kubernetes/manifests/kube-controller-manager.yaml 
spec:
  containers:
  - command:
    - kube-controller-manager
    - --allocate-node-cidrs=true
......
    # 增加下面三行参数
    - --horizontal-pod-autoscaler-sync-period=10s
    - --horizontal-pod-autoscaler-initial-readiness-delay=20s
    - --horizontal-pod-autoscaler-downscale-stabilization=60s

保存退出,静态 Pod 会自动重启生效

Horizontal Pod Autoscaler

HPA 作用

控制器将从一系列API(metrics.k8s.iocustom.metrics.k8s.ioexternal.metrics.k8s.io)中获取度量值。 metrics.k8s.io API 通常由Metrics Server提供。根据 HPA 中定义的指标动态实现控制器中pod伸缩,支持replication controller、deployment和replicaset。

适用场景

  • 流量波动大的无状态服务(nginx、api、网关、微服务)
  • 需要提高并发削峰填谷
  • Deployment/StatefulSet 都支持

核心特点

  • 不修改 Pod 配置,只改副本数
  • 实时、秒级扩缩
  • 最常用、最稳定

支持指标

  • CPU 使用率
  • 内存使用率
  • 自定义指标(Prometheus 对接)
  • QPS、延迟等

基于 CPU 使用率伸缩

准备资源
bash 复制代码
root@master30:~# kubectl create deployment web --image=docker.io/library/nginx
root@master30:~# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-68b95c775c-xksf4   1/1     Running   0          4s
创建 hpa
bash 复制代码
Usage:  kubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS]--max=MAXPODS [--cpu-percent=CPU] [options]

root@master30:~# kubectl autoscale deployment web --max=5 --min=2 --cpu-percent=80
root@master30:~# kubectl get hpa web -o yaml |tee hpa-cpu.yaml
# 省略部分不重要配置
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  maxReplicas: 5
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 80
        type: Utilization
    type: Resource
  minReplicas: 2
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
# 稍等片刻,创建一个新的pod
root@master30:~# kubectl get pods
root@master30:~# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-68b95c775c-48ngs   1/1     Running   0          13s
web-68b95c775c-xksf4   1/1     Running   0          41s

root@master30:~# kubectl get hpa
NAME   REFERENCE        TARGETS              MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: <unknown>/80%   2         5         2          34s
# CPU目标为unknown

要想看到 HPA 的 TARGETS 值必须满足2个条件:

  1. 安装 metric server。
  2. 为 pod 设定资源限制。
bash 复制代码
root@master30:~# kubectl edit deployments.apps web
# 修改spec.template.spec.containers.[N].resources属性,添加limit属性,如下:
        resources:
          limits: 
            cpu: 100m
            memory: 200Mi

# 再次查看hpa
root@master30:~# kubectl get hpa
NAME   REFERENCE        TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: 0%/80%   2         5         2          83s

root@master30:~# kubectl expose deployment web --port=80 --target-port=80
root@master30:~# kubectl get svc
NAME   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
web    ClusterIP   10.100.255.92   <none>        80/TCP    6s
压力测试
bash 复制代码
# 打开一个监控窗口
root@master30:~# \
while true
do
  kubectl get hpa;echo
  kubectl get pod;echo
  kubectl top pods
  sleep 1
done

# 上 CPU 压力
root@master30:~# apt install -y apache2-utils
root@master30:~# while true ;do ab -n 300000 -c 100 http://10.100.255.92/;sleep 1;done
#  -n 300000,总请求数
#  -c 100,每次并发数

CPU负载 cpu: 98%

bash 复制代码
Every 2.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 09:57:22 2026

NAME   REFERENCE        TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: 100%/80%   2         5         2          8m32s

NAME                   CPU(cores)   MEMORY(bytes)   
web-6dcdc45c94-6gwd2   101m         3Mi             
web-6dcdc45c94-dvd2m   100m         3Mi 

超过目标值后,HPA 新建了一个pod

复制代码
Every 2.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 09:58:04 2026

NAME   REFERENCE        TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: 95%/80%   2         5         3          9m14s

NAME                   CPU(cores)   MEMORY(bytes)   
web-6dcdc45c94-2zbmb   93m          3Mi             
web-6dcdc45c94-6gwd2   100m         3Mi             
web-6dcdc45c94-dvd2m   90m          3Mi 

HPA又新建了一个pod

bash 复制代码
Every 2.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 09:58:59 2026

NAME   REFERENCE        TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: 99%/80%   2         5         4          11m

NAME                   CPU(cores)   MEMORY(bytes)   
web-6dcdc45c94-2zbmb   100m         3Mi             
web-6dcdc45c94-6gwd2   100m         3Mi             
web-6dcdc45c94-dvd2m   97m          3Mi             
web-6dcdc45c94-tsjkr   99m          3Mi

HPA又新建了一个pod

bash 复制代码
Every 2.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 09:59:59 2026

NAME   REFERENCE        TARGETS        MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   cpu: 100%/80%   2         5         5          11m

NAME                   CPU(cores)   MEMORY(bytes)   
web-6dcdc45c94-2zbmb   101m         3Mi             
web-6dcdc45c94-6gwd2   100m         3Mi             
web-6dcdc45c94-dvd2m   100m         3Mi             
web-6dcdc45c94-hpg45   98m          3Mi             
web-6dcdc45c94-tsjkr   101m         3Mi 

观察过程:

  1. 随着pod CPU使用率上升,自动扩展pod数量。
  2. 正常情况,30秒左右创建一个新pod,
  3. 即使pod CPU使用率超过阈值,但pod数量不会超过5。
  4. 停止压力测试,负载降低后,pod数量立刻减少为2。
清理资源
bash 复制代码
# 删除 hpa
root@master30:~# kubectl delete hpa web 

# 删除 deployment
root@master30:~# kubectl delete deployment web

# 保留 svc,后续使用

基于 Mem 使用率伸缩

我们仍然以nginx应用实践。想要Nginx 内存涨,要访问会占用内存的页面 。最简单方法:让 Nginx 返回一个超大响应体

准备资源
bash 复制代码
# worker节点创建big.img
[root@worker31 ~]# mkdir /www
[root@worker31 ~]# dd if=/dev/zero of=/www/big.img bs=1M count=200
[root@worker32 ~]# mkdir /www
[root@worker32 ~]# dd if=/dev/zero of=/www/big.img bs=1M count=200

root@master30:~# vim deployment-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: big-file
          mountPath: /usr/share/nginx/html
        resources:
          limits:
            cpu: 100m
            memory: 200Mi
      volumes:
      - name: big-file
        hostPath:
          path: /www
root@master30:~# kubectl apply -f deployment-web.yaml
创建 hpa
bash 复制代码
root@master30:~# vim hpa-mem.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  maxReplicas: 5
  metrics:
  - resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 60
    type: Resource
  minReplicas: 2
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
root@master30:~# kubectl apply -f hpa-mem.yaml
root@master30:~# kubectl get hpa
NAME   REFERENCE        TARGETS                 MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: <unknown>/60%   2         5         1          13m

# 目标值为空

# 稍等片刻,创建一个新的pod
root@master30:~# kubectl get pods
NAME                   READY   STATUS    RESTARTS   AGE
web-6dcdc45c94-2zj8s   1/1     Running   0          13m
web-6dcdc45c94-w62pr   1/1     Running   0          13s

# 稍等一会,再次查看
root@master30:~# kubectl get hpa
NAME   REFERENCE        TARGETS          MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: 1%/60%   2         5         2          53s
压力测试
bash 复制代码
# 打开一个监控窗口
root@master30:~# watch -n 4 'kubectl get hpa;echo;kubectl top pods'

# 上 MEM 压力
root@master30:~# while true ;do ab -n 300000 -c 100 http://10.99.129.137/big.img;sleep 1;done

负载上来了

bash 复制代码
Every 4.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 11:13:29 2026

NAME   REFERENCE        TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: 86%/60%   2         5         2          16m

NAME                  CPU(cores)   MEMORY(bytes)
web-88cff78bb-2b7vh   15m          174Mi
web-88cff78bb-76pg2   15m          171Mi

新建了一个pods

复制代码
Every 4.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 11:13:46 2026

NAME   REFERENCE        TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: 58%/60%   2         5         3          16m

NAME                  CPU(cores)   MEMORY(bytes)
web-88cff78bb-2b7vh   15m          174Mi
web-88cff78bb-4hcm5   5m           3Mi
web-88cff78bb-76pg2   15m          171Mi

又新建了一个pods

bash 复制代码
Every 4.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 11:15:46 2026

NAME   REFERENCE        TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: 58%/60%   2         5         4          16m

NAME                  CPU(cores)   MEMORY(bytes)
web-88cff78bb-2b7vh   15m          174Mi
web-88cff78bb-4hcm5   5m           3Mi
web-88cff78bb-76pg2   15m          171Mi
web-88cff78bb-ws6t4   1m           3Mi  

又新建了一个pods

bash 复制代码
Every 4.0s: kubectl get hpa;echo;kubectl top pods                     master30.laoma.cloud: Sun Apr 19 11:17:46 2026

NAME   REFERENCE        TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   memory: 58%/60%   2         5         5          16m

NAME                  CPU(cores)   MEMORY(bytes)
web-88cff78bb-2b7vh   15m          174Mi
web-88cff78bb-4hcm5   5m           3Mi
web-88cff78bb-76pg2   15m          171Mi
web-88cff78bb-ws6t4   1m           3Mi  
web-88cff78bb-t4q2p   100m         3Mi

观察过程:

  1. 随着pod MEM使用率上升,自动扩展pod数量。
  2. 即使pod MEM使用率超过阈值,但pod数量不会超过5。
清理资源
bash 复制代码
# 删除 hpa
root@master30:~# kubectl delete hpa web 

# 删除 deployment
root@master30:~# kubectl delete deployment web

# 删除 svc
root@master30:~# kubectl delete svc web 

Vertical Pod Autoscaler

VPA 作用

控制器将从一系列API(metrics.k8s.iocustom.metrics.k8s.ioexternal.metrics.k8s.io)中获取度量值,metrics.k8s.io API 通常由Metrics Server提供。根据 VPA 中定义的指标动态调整 Pod 的 requests 和 limits

VPA 适用场景

  • 资源配置不合理的服务
  • 长期运行、流量稳定的服务
  • Java、Go 等内存占用固定的应用
  • 不适合频繁扩缩的服务

VPA 核心特点

  • 不改变 Pod 数量
  • 自动给 Pod 推荐 / 设置 CPU / 内存
  • 生效需要重启 Pod(默认)
  • 比 HPA 少用,因为有侵入性

HPA 与 VPA 对比

项目 HPA 横向扩缩容 VPA 纵向扩缩容
全称 Horizontal Vertical
扩缩方式 增加 / 减少 Pod 数量 调整 CPU / 内存 request/limit
是否重启 Pod ❌ 不重启 ✅ 一般需要重启
适合负载 流量波动大 资源配置不合理
生效速度
稳定性
生产使用 非常普遍 较少
能否一起开 不能同时开(会冲突) -
支持资源 CPU、内存、自定义 CPU、内存

Quota and Limits

环境准备

  1. 创建一个独立的名字空间quota,并切换到该ns
bash 复制代码
root@master30:~# kubectl create ns quota root@master30:~# kubectl config set-context --current --namespace quota
  1. 提前部署好 Metric Server

ResourceQuota

**问题:**当多个用户或团队共享Kubernetes集群时,有人会使用超过其基于公平原则所分配到的资源量。

**解决:**可以使用资源配额限制 Namespace 使用的资源。

资源配额 ,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。

资源配额的工作方式如下:

  • 不同的团队在不同的命名空间下工作。这可以通过 RBAC 强制执行。
  • 集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。
  • 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况, 以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。
  • 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。
  • 如果命名空间下的计算资源 (如 cpumemory)的配额被启用, 则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。

提示: 可使用 LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。

启用资源配额

Kubernetes 默认启用了资源配额功能 。 当 API 服务器 的命令行标志 --enable-admission-plugins= 中包含 ResourceQuota 时, 资源配额会被启用。

当命名空间中存在一个 ResourceQuota 对象时,对于该命名空间而言,资源配额就是开启的。

配额类型

Kubernetes可以限制两种类型资源:

  • 对象数量:Kubernetes 资源数量,例如pods,services等。

实施资源数量配额可以提高kubernetes稳定性,避免Etcd数据库无限增长,还可以避免占用node中其他功能资源(例如ip地址服务)。

  • 计算资源:物理或者虚拟资源容量,例如 CPU,memory 和存储容量。

实施计算资源配额可以避免消耗 kubernetes 集群中单个node所有计算资源,避免单个namespace中应用消耗所有集群资源,导致其他namespace中应用无法正常运行。

**kubernetes 通过 ResourceQuota 类型资源实施配额。**一个namespace可以包含多个ResourceQuota对象,这些限制是累加的,一般情况,多个ResourceQuota对象不会限定同一个资源。

  • 对象数量:
  • persistentvolumeclaims
  • services
  • secrets
  • configmaps
  • replicationcontrollers
  • deployments.apps
  • replicasets.apps
  • statefulsets.apps
  • jobs.batch
  • cronjobs.batch
  • 计算资源
资源名称 描述
limits.cpu 在所有处于非终止状态的 Pod 中,CPU 限制的总和不能超过此值。
limits.memory 在所有处于非终止状态的 Pod 中,内存限制的总和不能超过这个值。
requests.cpu 在所有处于非终止状态的 Pod 中,CPU 请求的总和不能超过此值。
requests.memory 在所有处于非终止状态的 Pod 中,内存请求的总和不能超过这个值。
requests.storage 在所有持久卷声明中,存储请求的总和不能超过此值。
cpu requests.cpu一样
memory requests.memory一样

单位说明:

  • CPU1 cpu 等于1000 m,默认单位是 cpu核心数量。
  • memory:支持两种格式。
  • Ki | Mi | Gi | Ti | Pi | Ei,进制是1024,例如1024 = 1Ki
  • k | M | G | T | P | E,进制是1000,例如1000 = 1k
  • 默认单位是 G,例如1.5,代表1500M。

配额管理

重要说明: 如果项目级别配额限定了 requestlimit,那么创建pod的时候必须指定 requestlimit

创建 ResourceQuota 对象

bash 复制代码
root@master30:~# kubectl create quota myquota --hard=pods=2,services=3,secrets=5,persistentvolumeclaims=10

root@master30:~# kubectl get resourcequotas 
NAME       AGE   REQUEST                                                                LIMIT
my-quota   10s   persistentvolumeclaims: 0/10, pods: 0/2, secrets: 1/5, services: 0/3

root@master30:~# kubectl describe quota myquota 
Name:                   myquota
Namespace:              quota
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
pods                    0     2
secrets                 1     5
services                0     3

通过 yaml 文件创建

yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    persistentvolumeclaims: "10"
    pods: "2"
    secrets: "5"
    services: "3"

测试配额

bash 复制代码
root@master30:~# kubectl create deployment web --image=hub.laoma.cloud/library/nginx --replicas=3 
root@master30:~# kubectl get all
NAME                      READY   STATUS    RESTARTS   AGE
pod/web-96d5df5c8-dl7qk   1/1     Running   0          40s
pod/web-96d5df5c8-j7fhh   1/1     Running   0          40s

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   2/3     2            2           40s

NAME                            DESIRED   CURRENT   READY   AGE
replicaset.apps/web-96d5df5c8   3         2         2       40s

root@master30:~# kubectl describe rs web-96d5df5c8
LAST SEEN   TYPE      REASON              OBJECT                     MESSAGE
......
33s         Warning   FailedCreate        replicaset/web-96d5df5c8   Error creating: pods "web-96d5df5c8-xg6c9" is forbidden: exceeded quota: myquota, requested: pods=1, used: pods=2, limited: pods=2
2s          Warning   FailedCreate        replicaset/web-96d5df5c8   (combined from similar events): Error creating: pods "web-96d5df5c8-89p7j" is forbidden: exceeded quota: myquota, requested: pods=1, used: pods=2, limited: pods=2
25s         Normal    SuccessfulCreate    replicaset/web-96d5df5c8   Created pod: web-96d5df5c8-bkzmd
34s         Normal    ScalingReplicaSet   deployment/web             Scaled up replica set web-96d5df5c8 to 3

# 超过配额,创建失败

# 修改配额 pod数量为10
root@master30:~# kubectl patch resourcequotas myquota -p '{"spec":{"hard":{"pods":10}}}'

# 此时重新扩展rs
root@master30:~# kubectl scale rs web-96d5df5c8 --replicas 3

# 再次验证pod数量
root@master30:~# kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
pod/web-96d5df5c8-ajcz2   1/1     Running   0          2s
pod/web-96d5df5c8-dl7qk   1/1     Running   0          60s
pod/web-96d5df5c8-j7fhh   1/1     Running   0          60s

Request 和 Limits

如果命名空间下的计算资源 (如 cpumemory)的配额被启用, 则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。

pod.containers.resources 定义包含两部分:

  • requests ,指明pod运行需要的最少计算资源,调度器查找具有充足计算资源的nodes。
  • limits ,指明pod运行可以获得节点最多计算资源,用于阻止pod占用node太多计算资源。node使用Linux内核功能cgroup,限制pod资源使用。

测试-不指定计算资源

配额示例

bash 复制代码
root@master30:~# vim resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    persistentvolumeclaims: "10"
    pods: "2"
    secrets: "5"
    services: "3"
    requests.cpu: 1000m
    requests.memory: "2048Mi"
    limits.cpu: 1000m
    limits.memory: "2048Mi"
root@master30:~# kubectl apply -f resourcequota.yaml

pod 示例

bash 复制代码
root@master30:~# vim pod-without-quota.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: httpd
    imagePullPolicy: IfNotPresent
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
root@master30:~# kubectl apply -f pod-without-quota.yaml
Error from server (Forbidden): error when creating "pod-without-quota.yaml": pods "web" is forbidden: failed quota: myquota: must specify limits.cpu for: web; limits.memory for: web; requests.cpu for: web; requests.memory for: web

# 清理环境
root@master30:~# kubectl delete resourcequotas myquota

测试-Request

配额示例

bash 复制代码
root@master30:~# vim resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    requests.cpu: 1000m
    requests.memory: "2048Mi"
root@master30:~# kubectl apply -f resourcequota.yaml

pod 示例1:超上限

bash 复制代码
root@master30:~# vim pod-request-1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 2000m
        memory: 4096Mi
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
root@master30:~# kubectl apply -f pod-request-1.yaml
Error from server (Forbidden): error when creating "pod-request-1.yaml": pods "web" is forbidden: exceeded quota: myquota, requested: requests.cpu=2,requests.memory=4Gi, used: requests.cpu=0,requests.memory=0, limited: requests.cpu=1,requests.memory=2Gi

pod 示例2:未超上限

bash 复制代码
root@master30:~# vim pod-request-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 200m
        memory: 1024Mi
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
root@master30:~# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
web    1/1     Running   0          43s

# 验证使用情况
root@master30:~# kubectl describe resourcequotas myquota 
Name:            myquota
Namespace:       quota
Resource         Used  Hard
--------         ----  ----
requests.cpu     200m  1
requests.memory  1Gi   2Gi

# 删除pod和quota
root@master30:~# kubectl delete pod web
root@master30:~# kubectl delete resourcequotas myquota

测试-Limits

压力测试镜像
bash 复制代码
Usage: stress [OPTION [ARG]] ...
 -?, --help         show this help statement
     --version      show version statement
 -v, --verbose      be verbose
 -q, --quiet        be quiet
 -n, --dry-run      show what would have been done
 -t, --timeout N    timeout after N seconds
     --backoff N    wait factor of N microseconds before work starts
 -c, --cpu N        spawn N workers spinning on sqrt()
 -i, --io N         spawn N workers spinning on sync()
 -m, --vm N         spawn N workers spinning on malloc()/free()
     --vm-bytes B   malloc B bytes per vm worker (default is 256MB)
     --vm-stride B  touch a byte every B bytes (default is 4096)
     --vm-hang N    sleep N secs before free (default none, 0 is inf)
     --vm-keep      redirty memory instead of freeing and reallocating
 -d, --hdd N        spawn N workers spinning on write()/unlink()
     --hdd-bytes B  write B bytes per hdd worker (default is 1GB)

Example: stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s

Note: Numbers may be suffixed with s,m,h,d,y (time) or B,K,M,G (size).

常用选项:

  • -c, --cpu N spawn N workers spinning on sqrt()
  • -m, --vm N spawn N workers spinning on malloc()/free()

--vm-bytes B malloc B bytes per vm worker (default is 256MB)

  • -d, --hdd N spawn N workers spinning on write()/unlink() --hdd-bytes B write B bytes per hdd worker (default is 1GB)

示例:

bash 复制代码
# 压力测试内存
$ docker run --name stress hub.laoma.cloud/progrium/stress -m 1 --vm-bytes 512M

# 压力测试CPU
$ docker run --name stress hub.laoma.cloud/progrium/stress -c 1

# 压力测试IO
$ docker run --name stress hub.laoma.cloud/progrium/stress --d 1 --hdd-bytes 3G

对于 pod:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    command: ['sh','-c','sleep 3600']
    # 或者不用command,而是使用args作为参数传递给镜像的Entrypoint。
    #args: ['-m','1','--vm-bytes','512M']
    #args: ['-c','1']
    #args: ['-d','1','--hdd-bytes','3G']
配额示例
bash 复制代码
root@master30:~# vim resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    limits.cpu: 1000m
    limits.memory: "2048Mi"
root@master30:~# kubectl apply -f resourcequota.yaml
测试 CPU 资源

pod示例:

bash 复制代码
root@master30:~# vim pod-limit-cpu.yaml
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']
    resources:
      limits:
        cpu: 200m
        memory: "256Mi"
root@master30:~# kubectl apply -f pod-limit-cpu.yaml

打开一个终端监控

kubectl top 命令需要提前部署Metrics-Server

bash 复制代码
root@master30:~# kubectl top pods
NAME     CPU(cores)   MEMORY(bytes)   
stress   201m         0Mi

**可以发现:**CPU 使用率维持在 200m 左右。

bash 复制代码
# 删除 pod
root@master30:~# kubectl delete pod stress --force
测试 MEMORY 资源

pod示例:

bash 复制代码
root@master30:~# vim pod-limit-memory.yaml
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-m','1','--vm-bytes','512M']
    resources:
      limits:
        cpu: 200m
        memory: "256Mi"
root@master30:~# kubectl apply -f pod-limit-memory.yaml

打开一个终端监控

bash 复制代码
root@master30:~# kubectl get pods -w
NAME     READY   STATUS      RESTARTS     AGE
stress   0/1     OOMKilled   1 (2s ago)   3s
stress   0/1     CrashLoopBackOff   1 (2s ago)   4s

可以发现: Pod 状态为 OOMKilled,并进行restart。

bash 复制代码
# 删除 pod he 
root@master30:~# kubectl delete pod stress --force
root@master30:~# kubectl delete resourcequotas myquota
总结
  1. 计算资源的 limits 总和是否会超过节点上资源总和?

答案:可能会。 假设 node可用MEMORY为1G。

每个pod内存 requests是256M,limit是512M。创建5个pod,pod实际占用内存也为256M(有可能小于256M)。

node上大概可以创建4个pod,而此时的limits总和是2G。

  1. 当计算资源的limits总和超过节点上资源总和时,kubernetes如何处理?
  • 对于 cpu ,kubernetes 认为 cpu 是可被压缩的资源,在应用达到limits时,减少该容器的调度时间,并不会杀死应用。
  • 对于 memory ,kubernetes 认为 memory 是无法被压缩的资源 ,此时k8s 会杀死占用资源超过其request的应用(1.9版本之后的版本)。首当其冲的是没有指定request的container,然后是使用资源超过其request更多的container。同等情况下优先级更低的container更容易被杀死。

LimitRange

kubernetes创建pod时,默认不指定资源请求和限制。如果namespace设置了配额,那么创建不指定资源请求和资源限制的pod是不允许的。为了在设定配额的namespace中使用pod,namespace还需要为pod资源请求设定默认范围

LimitRange 资源,也称为limits,定义了单个pod的资源请求和资源限制default、minimum、maximum值。pod的资源请求是其中所有容器请求的总和。

LimitRange 资源用于限定特定 namespace。

namespace设定了LimitRange,创建资源规则:

  • 如果项目中请求一个未提供计算资源的对象,那么此时namespace将使用limit范围default值创建该对象。
  • 如果项目中请求一个计算资源的对象,请求的资源小于limit最小值 ,那么该资源**无法创建**。
  • 如果项目中请求一个计算资源的对象,请求的资源大于limit最大值 ,那么该资源**无法创建**。

LimitRange 示例

bash 复制代码
root@master30:~# vim limits.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: mylimit
spec:
  limits:
    - type: Container
      max:
        memory: 1024Mi
        cpu: 1
      min:
        memory: 128Mi
        cpu: 100m
      default:
        memory: 512Mi
        cpu: 500m
      defaultRequest:
        memory: 256Mi
        cpu: 200m

说明:

  • name:只能使用小写字母,数字, '-' 和 '.',而且只能是数字或字母开头和结尾。
  • default:即该namespace配置resourceQuota时,创建container的默认limit上限
  • defaultRequest:即该namespace配置resourceQuota时,创建container的默认request上限
  • max:即该namespace下创建container的资源最大值
  • min:即该namespace下创建container的资源最小值

其中: min <= defaultRequest <= default <= max

bash 复制代码
root@master30:~# kubectl apply -f limits.yaml
root@master30:~# kubectl get limitranges 
NAME      CREATED AT
mylimit   2021-09-09T04:09:15Z

root@master30:~# kubectl describe limitranges mylimit 
Name:       mylimit
Namespace:  quota
Type        Resource  Min    Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---  ---------------  -------------  -----------------------
Container   cpu       100m   1    200m             500m           -
Container   memory    128Mi  1Gi  256Mi            512Mi          -

未指定 resources

示例1

bash 复制代码
root@master30:~# vim pod-without-limits.yaml
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']

**结论:**创建出来的pod的resources 与 limitranage 指定的相关默认值一致。

bash 复制代码
root@master30:~# kubectl apply -f pod-without-limits.yaml
root@master30:~# kubectl top pods
NAME     CPU(cores)   MEMORY(bytes)   
stress   501m         0Mi

root@master30:~# kubectl get pod stress -o yaml
......
spec:
  containers:
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    name: stress
    resources:
      limits:
        cpu: 500m
        memory: 512Mi
      requests:
        cpu: 200m
        memory: 256Mi
......
# 清理资源
root@master30:~# kubectl delete limitranges mylimit 
root@master30:~# kubectl delete pod stress --force 

只指定 limit 值

示例 2-1:limit 值大于 max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      limits:
        cpu: 1.1
        memory: 1100Mi
root@master30:~# kubectl apply -f limit.yml
Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [maximum cpu usage per Container is 1, but limit is 1100m, maximum memory usage per Container is 1Gi, but limit is 1181116006400m]
示例 2-2:limit 值小于 min 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      limits:
        cpu: 60m
        memory: 60Mi
root@master30:~# kubectl apply -f limit.yml
Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [minimum cpu usage per Container is 100m, but request is 60m, minimum memory usage per Container is 128Mi, but request is 60Mi]
示例 2-3:min 值< limit 值< max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      limits:
        cpu: 600m
        memory: 600Mi

结论:

  • 创建的容器limits值必须满足条件:min值<指定的limit值<max值
  • 当只指定limits值时,requests值与limits值保持一致,而不是default request。

只指定 requests

示例 3-1:requests 大于 max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      requests:
        cpu: 1600m
        memory: 600Mi
root@master30:~# kubectl apply -f limit4.yml 
The Pod "web" is invalid: 
* spec.containers[0].resources.requests: Invalid value: "1600m": must be less than or equal to cpu limit
* spec.containers[0].resources.requests: Invalid value: "1600Mi": must be less than or equal to memory limit
示例 3-2:requests 小于 min 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      requests:
        cpu: 60m
        memory: 60Mi
root@master30:~# kubectl apply -f limit.yml 
Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [minimum cpu usage per Container is 100m, but request is 60m, minimum memory usage per Container is 128Mi, but request is 60Mi]
示例 3-3:min 值< request 值< max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: hub.laoma.cloud/library/nginx
    resources:
      requests:
        cpu: 400m
        memory: 400Mi

结论:

  • 创建的容器requests值必须满足条件:min值<requests值<limits值
  • 当只指定requests值时,limits值与default值保持一致。

限定资源类型

LimitRange 资源可以限定如下资源:

Type Resource Name Description
container cpu、memory 限定容器 cpu、memroy
Pod cpu、memory 限定 Pod 中所有容器cpu、memroy的总和
PVC storage 限定PVC申请的存储空间大小

LimitRange for PVC 示例:

yaml 复制代码
apiVersion: v1
kind: LimitRange
metadata:
  name: storagelimits
spec:
  limits:
  - type: PersistentVolumeClaim
    max:
      storage: 2Gi
    min:
      storage: 1Gi
相关推荐
梦想的颜色1 小时前
Docker 容器化本地部署 Claude Code 完整硬核教程|隔离沙盒 + 国产模型直连 + 持久化 Skill
运维·容器·ai 工程化·沙盒隔离·docker 本地部署·claude code硬核实战·国内国产模型接入
摇滚侠2 小时前
云原生 Java 架构师的第一课 K8s+Docker+KubeSphere+DevOps 19-25
java·云原生·kubernetes
渣渣盟2 小时前
Docker 运维常用命令手册(含扩容与实战)
运维·docker·容器
咕噜咕噜的猪大侠4 小时前
《K8s 核心知识梳理:Deployment 滚动更新、JobCronJob、DaemonSet 和 Service》
云原生·容器·kubernetes
摇滚侠4 小时前
云原生 Java 架构师的第一课 K8s+Docker+KubeSphere+DevOps 26-40
java·云原生·kubernetes
大侠锅锅20 小时前
第 4 篇:策略模式实践——用统一接口管理 Docker 容器、原生进程与 K3s Pod
docker·容器·边缘计算·策略模式·iot
小蓝波1 天前
docker 的命令
java·docker·容器
2301_801184751 天前
docker 工作
java·docker·容器