一、Pod资源限制到底是个啥玩意儿

咱们先打个比方吧。Kubernetes里的Pod就像是个小公寓,里面住着你的应用容器。资源限制呢,就是给这个公寓定规矩——水电气用量不能超标,否则整栋楼都得遭殃。

在Kubernetes里主要通过这两个参数来控制:

  • requests:相当于"最低生活保障"
  • limits:就是"最高消费限额"

举个实际例子(技术栈:Kubernetes YAML):

apiVersion: v1
kind: Pod
metadata:
  name: my-webapp
spec:
  containers:
  - name: web-container
    image: nginx:latest
    resources:
      requests:
        memory: "256Mi"  # 至少给我256MB内存
        cpu: "500m"     # 至少0.5个CPU核心
      limits:
        memory: "512Mi"  # 最多只能用512MB
        cpu: "1"        # CPU最多用1个核心

二、没设限制会出啥乱子

2.1 内存泄漏变"楼霸"

想象有个容器像贪吃蛇一样不停吃内存,又不设限制。我在生产环境就遇到过这样的惨案:

# 危险示范!没有内存限制的Pod
apiVersion: v1
kind: Pod
metadata:
  name: memory-hog
spec:
  containers:
  - name: bad-container
    image: my-app:v1
    # 这里完全没设resources限制!

结果这货一运行就把节点内存吃光了,导致:

  1. 节点上的其他Pod集体被OOM Killer干掉
  2. kubelet进程因为内存不足崩溃
  3. 整个节点直接失联

2.2 CPU争抢像早高峰地铁

再看个CPU的例子:

# 两个Pod抢CPU的典型场景
apiVersion: v1
kind: Pod
metadata:
  name: cpu-hog-1
spec:
  containers:
  - name: loop
    image: busybox
    command: ["sh", "-c", "while true; do echo 'Eating CPU'; done"]

---

apiVersion: v1
kind: Pod
metadata: 
  name: important-service
spec:
  containers:
  - name: app
    image: my-important-service:v2

这时候第一个Pod会像饿狼一样抢走所有CPU,导致重要服务响应延迟飙升到5秒以上。

三、设置不当的几种作死姿势

3.1 限制值比请求值还低

见过最离谱的配置是这样的:

resources:
  requests:
    memory: "1Gi"
    cpu: "1"
  limits:
    memory: "512Mi"  # 限制比请求还小!
    cpu: "500m"

这就好比跟房东说:"我每天至少要1吨水,但你别给我超过半吨"。结果就是Pod永远无法被调度,陷入Pending状态。

3.2 忘记设置默认LimitRange

很多新手不知道可以用LimitRange设置默认值,导致集群里一堆"裸奔"的Pod。正确的做法是:

apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
spec:
  limits:
  - default:         # 默认限制
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:   # 默认请求
      cpu: "100m"
      memory: "128Mi"
    type: Container

3.3 不对特殊容器做例外处理

比如某些初始化容器需要更多资源:

initContainers:
- name: data-loader
  image: loader:v3
  resources:
    requests:
      memory: "2Gi"  # 初始化需要大内存
      cpu: "2"
    limits:
      memory: "4Gi"
      cpu: "4"
containers:
- name: main-app
  image: app:v2
  resources:
    requests:
      memory: "512Mi"
      cpu: "500m"
    limits:
      memory: "1Gi"
      cpu: "1"

四、正确姿势与最佳实践

4.1 黄金比例设置法

经过多年实践,我总结出这个内存设置公式:

limits = requests × 1.5

比如:

resources:
  requests:
    memory: "256Mi"
    cpu: "500m"
  limits:
    memory: "384Mi"  # 256 × 1.5
    cpu: "750m"     # 500 × 1.5

4.2 使用Vertical Pod Autoscaler

Kubernetes有个神器叫VPA,能自动调整资源限制:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"  # 自动调整资源

4.3 监控与警报配置

必须配好监控,这里给个Prometheus的告警规则示例:

- alert: PodMemoryNearLimit
  expr: (container_memory_working_set_bytes / container_spec_memory_limit_bytes) > 0.9
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: Pod {{ $labels.pod }} is using >90% of its memory limit

五、不同场景的特殊处理

5.1 Java应用的专属配置

JVM应用需要额外注意,因为JVM自己还有内存管理:

env:
- name: JAVA_OPTS
  value: "-Xms256m -Xmx256m"  # 必须小于Pod的memory request
resources:
  requests:
    memory: "300Mi"  # 比Xmx多50MB左右
    cpu: "500m"
  limits:
    memory: "500Mi"
    cpu: "1"

5.2 机器学习训练任务

GPU任务需要特殊处理:

resources:
  requests:
    nvidia.com/gpu: 1  # 申请GPU
    memory: "8Gi"
    cpu: "2"
  limits:
    nvidia.com/gpu: 1
    memory: "16Gi" 
    cpu: "4"

六、总结与避坑指南

经过这些年的摸爬滚打,我总结了这些血泪教训:

  1. 永远要设置requests和limits
  2. 重要应用应该设置Guaranteed QoS(requests=limits)
  3. 定期检查资源使用率,避免"僵尸限制"
  4. 使用ResourceQuota防止命名空间资源失控
  5. 记得为DaemonSet设置合理的资源限制

最后给个完整的示范配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: perfect-app
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: app
        image: perfect-app:v3
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1"
            memory: "768Mi"  # 1.5倍原则
        livenessProbe:
          httpGet:
            path: /health
            port: 8080

记住:合理的资源限制就像交通规则,看似约束,实则是为了保护整个系统的顺畅运行。