资源管理 - Requests & Limits

资源管理 - Requests & Limits

为什么需要资源管理

在 Kubernetes 中,如果不限制资源:

  • 资源争抢:一个 Pod 占用所有资源
  • 性能下降:节点资源耗尽导致所有 Pod 变慢
  • 不可预测:无法保证应用性能
  • 成本失控:资源浪费

Requests 和 Limits

Requests(资源请求)

调度器用于选择节点的最小资源保证。

Limits(资源限制)

容器运行时的最大资源限制。

基础配置

apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: nginx
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

含义

  • 保证至少分配 64Mi 内存和 0.25 核 CPU
  • 最多使用 128Mi 内存和 0.5 核 CPU

CPU 资源

单位说明

  • 1 CPU = 1000m (millicores)
  • 500m = 0.5 核
  • 100m = 0.1 核
resources:
  requests:
    cpu: "1"      # 1 核心
    cpu: "1000m"  # 1 核心(等价)
    cpu: "500m"   # 0.5 核心
    cpu: "100m"   # 0.1 核心

CPU 限制行为

超出 Limits

  • 进程被限流(throttled)
  • 不会被杀死
  • 响应变慢
# 查看 CPU 限流
kubectl top pod <pod-name>

示例:CPU 密集型应用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cpu-intensive
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cpu-intensive
  template:
    metadata:
      labels:
        app: cpu-intensive
    spec:
      containers:
      - name: app
        image: cpu-app:v1
        resources:
          requests:
            cpu: "1"
            memory: "512Mi"
          limits:
            cpu: "2"
            memory: "1Gi"

内存资源

单位说明

resources:
  requests:
    memory: "128Mi"   # 128 MiB
    memory: "1Gi"     # 1 GiB
    memory: "1024Mi"  # 1024 MiB = 1 GiB
    memory: "128M"    # 128 MB (1000进制)
    memory: "1G"      # 1 GB (1000进制)

推荐使用:Mi、Gi(1024进制)

内存限制行为

超出 Limits

  • Pod 被 OOMKilled(Out Of Memory Killed)
  • Pod 会自动重启(如果 restartPolicy 允许)
# 查看 OOM 事件
kubectl describe pod <pod-name>

# 输出
Events:
  Type     Reason     Age   From     Message
  ----     ------     ----  ----     -------
  Warning  OOMKilled  1m    kubelet  Container killed due to OOM

示例:内存密集型应用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: memory-intensive
spec:
  replicas: 1
  selector:
    matchLabels:
      app: memory-intensive
  template:
    metadata:
      labels:
        app: memory-intensive
    spec:
      containers:
      - name: app
        image: memory-app:v1
        resources:
          requests:
            cpu: "500m"
            memory: "2Gi"
          limits:
            cpu: "1"
            memory: "4Gi"

QoS(服务质量等级)

Kubernetes 根据 requests 和 limits 自动分配 QoS 等级。

1. Guaranteed(最高优先级)

条件

  • 每个容器都设置了 requests 和 limits
  • requests 等于 limits
resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"

特点

  • 资源有保证
  • 最后被驱逐
  • 适合关键应用

2. Burstable(中等优先级)

条件

  • 至少一个容器设置了 requests 或 limits
  • 不满足 Guaranteed 条件
resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "1"
    memory: "1Gi"

特点

  • 可以使用额外资源
  • 中等驱逐优先级
  • 适合一般应用

3. BestEffort(最低优先级)

条件

  • 没有设置任何 requests 和 limits
# 没有 resources 配置

特点

  • 可以使用所有空闲资源
  • 首先被驱逐
  • 适合批处理任务

查看 QoS

kubectl describe pod <pod-name> | grep "QoS Class"

# 输出
QoS Class:       Guaranteed

LimitRange

为 Namespace 设置资源默认值和限制。

创建 LimitRange

apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-mem-limit-range
  namespace: dev
spec:
  limits:
  # 容器级别
  - type: Container
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "100m"
      memory: "128Mi"
    max:
      cpu: "2"
      memory: "2Gi"
    min:
      cpu: "50m"
      memory: "64Mi"
    maxLimitRequestRatio:
      cpu: 4
      memory: 4
  # Pod 级别
  - type: Pod
    max:
      cpu: "4"
      memory: "4Gi"

效果

  • 未指定资源的 Pod 自动应用 default 值
  • 超出 max 的 Pod 无法创建
  • 低于 min 的 Pod 无法创建
  • limits/requests 比例不能超过 maxLimitRequestRatio

ResourceQuota

限制 Namespace 的总资源使用。

创建 ResourceQuota

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev
spec:
  hard:
    # CPU 和内存
    requests.cpu: "10"
    requests.memory: "20Gi"
    limits.cpu: "20"
    limits.memory: "40Gi"
    # Pod 数量
    pods: "50"
    # 存储
    persistentvolumeclaims: "10"
    requests.storage: "100Gi"
kubectl describe resourcequota compute-quota -n dev

# 输出
Name:                  compute-quota
Namespace:             dev
Resource               Used  Hard
--------               ----  ----
limits.cpu             5     20
limits.memory          10Gi  40Gi
pods                   20    50
requests.cpu           2.5   10
requests.memory        5Gi   20Gi

按 QoS 限制

apiVersion: v1
kind: ResourceQuota
metadata:
  name: qos-quota
  namespace: dev
spec:
  hard:
    pods: "50"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values:
      - high

实战示例

数据库 Pod

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        resources:
          requests:
            cpu: "1"
            memory: "2Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 50Gi

Web 应用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
spec:
  replicas: 5
  selector:
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: webapp:v1
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5

批处理任务

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-job
spec:
  template:
    spec:
      containers:
      - name: worker
        image: batch-worker:v1
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
      restartPolicy: OnFailure

监控资源使用

Metrics Server

安装:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

查看资源使用:

# 节点资源
kubectl top nodes

# 输出
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
node-1   2500m        62%    8Gi             50%
node-2   1800m        45%    6Gi             37%

# Pod 资源
kubectl top pods

# 输出
NAME            CPU(cores)   MEMORY(bytes)
webapp-abc123   250m         128Mi
webapp-def456   180m         96Mi

# 指定 namespace
kubectl top pods -n kube-system

# 排序
kubectl top pods --sort-by=cpu
kubectl top pods --sort-by=memory

资源使用趋势

# 持续监控
watch kubectl top pods

# 查看容器资源
kubectl top pod <pod-name> --containers

最佳实践

1. 始终设置 Requests

resources:
  requests:
    cpu: "100m"
    memory: "128Mi"

原因

  • 确保调度器正确放置 Pod
  • 避免节点过载

2. 合理设置 Limits

resources:
  limits:
    cpu: "1"
    memory: "512Mi"

原则

  • limits 应该是 requests 的 2-4 倍
  • 避免设置过高的 limits

3. 避免 BestEffort

生产环境应避免不设置资源的 Pod。

4. 分层设置资源

集群 → Namespace (ResourceQuota) → Pod (Resources)

5. 监控和调优

# 定期检查资源使用
kubectl top nodes
kubectl top pods

# 调整资源配置
kubectl set resources deployment webapp \
  --requests=cpu=200m,memory=256Mi \
  --limits=cpu=500m,memory=512Mi

6. 使用垂直 Pod 自动扩缩容(VPA)

自动调整 requests 和 limits:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: webapp-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: webapp
  updatePolicy:
    updateMode: "Auto"

常见问题

Pod 一直 Pending

kubectl describe pod <pod-name>

# 可能原因
Events:
  Warning  FailedScheduling  1m  scheduler  0/3 nodes are available: insufficient cpu

解决

  • 降低 requests
  • 增加节点
  • 删除不需要的 Pod

Pod 频繁 OOMKilled

kubectl describe pod <pod-name>

Events:
  Warning  OOMKilled  1m  kubelet  Container killed due to OOM

解决

  • 增加 memory limits
  • 优化应用内存使用
  • 检查内存泄漏

CPU 限流

应用变慢,但未崩溃:

# 检查 CPU 使用
kubectl top pod <pod-name>

# 如果接近或超过 limits,增加 CPU 限制

小结

资源管理是 Kubernetes 集群稳定运行的基础:

核心概念

  • Requests:最小保证
  • Limits:最大限制
  • QoS:服务质量等级

关键配置

  • LimitRange:默认值和范围
  • ResourceQuota:总量限制

最佳实践

  • 始终设置 requests
  • 合理设置 limits
  • 监控资源使用
  • 定期优化配置

QoS 优先级

Guaranteed > Burstable > BestEffort

下一章我们将学习调度策略,控制 Pod 的调度行为。