OpenShift OKD 资源限制与调度实战指南

目标:掌握资源调度 —— 设置 CPU/内存限制 & 使用 NodeSelector


一、前置准备

1.1 环境检查

# 确认已登录 OKD 集群
oc whoami
oc cluster-info

# 查看集群节点状态
oc get nodes

# 查看节点详细信息(包括标签)
oc get nodes --show-labels

1.2 创建实验项目

# 创建独立的实验命名空间
oc new-project resource-demo

# 确认当前项目
oc project

二、设置 CPU / 内存限制

资源限制分为两个层次:

  • Pod 级别:直接在容器 spec 中设置 resources
  • 命名空间级别:通过 LimitRange 设置默认值,通过 ResourceQuota 设置总配额

2.1 Pod 级别资源限制

核心概念
字段 作用
requests 调度器用于选择节点的最低保证资源
limits 容器可使用的资源上限,超出将被限流(CPU)或 OOM Kill(内存)
创建带资源限制的 Pod
# resource-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: resource-demo-pod
  namespace: resource-demo
spec:
  containers:
  - name: demo-container
    image: nginx:latest
    resources:
      requests:
        cpu: "250m"        # 0.25 核(millicores)
        memory: "128Mi"    # 128 MiB
      limits:
        cpu: "500m"        # 0.5 核
        memory: "256Mi"    # 256 MiB
# 部署 Pod
oc apply -f resource-pod.yaml

# 验证资源配置
oc describe pod resource-demo-pod | grep -A 10 "Limits\|Requests"
创建带资源限制的 Deployment
# resource-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: resource-demo-deploy
  namespace: resource-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: resource-demo
  template:
    metadata:
      labels:
        app: resource-demo
    spec:
      containers:
      - name: app-container
        image: nginx:latest
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "300m"
            memory: "128Mi"
oc apply -f resource-deployment.yaml
oc get pods -n resource-demo
oc describe pod -l app=resource-demo -n resource-demo

2.2 命名空间级别:LimitRange(默认限制)

LimitRange 为没有显式声明资源的容器自动注入默认值。

# limitrange.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: demo-limitrange
  namespace: resource-demo
spec:
  limits:
  # ---- Container 级别限制 ----
  - type: Container
    default:             # 默认 limits(未声明时使用)
      cpu: "500m"
      memory: "256Mi"
    defaultRequest:      # 默认 requests(未声明时使用)
      cpu: "100m"
      memory: "64Mi"
    max:                 # 单个容器最大值
      cpu: "2"
      memory: "1Gi"
    min:                 # 单个容器最小值
      cpu: "50m"
      memory: "32Mi"
  # ---- Pod 级别限制 ----
  - type: Pod
    max:
      cpu: "4"
      memory: "2Gi"
# 应用 LimitRange
oc apply -f limitrange.yaml

# 查看生效的 LimitRange
oc describe limitrange demo-limitrange -n resource-demo

# 测试:创建一个不带资源声明的 Pod,观察是否自动注入
oc run test-auto --image=nginx --restart=Never -n resource-demo
oc describe pod test-auto -n resource-demo | grep -A 6 "Limits\|Requests"

2.3 命名空间级别:ResourceQuota(总配额)

ResourceQuota 限制整个命名空间的资源总量。

# resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: demo-quota
  namespace: resource-demo
spec:
  hard:
    # 计算资源配额
    requests.cpu: "2"          # 所有容器 requests.cpu 总和
    requests.memory: "2Gi"
    limits.cpu: "4"            # 所有容器 limits.cpu 总和
    limits.memory: "4Gi"
    # 对象数量配额
    pods: "10"                 # 最多 10 个 Pod
    services: "5"
    persistentvolumeclaims: "5"
# 应用配额
oc apply -f resourcequota.yaml

# 查看当前配额使用情况
oc describe resourcequota demo-quota -n resource-demo

# 实时监控配额
oc get resourcequota demo-quota -n resource-demo -o yaml

2.4 验证资源限制效果

# 尝试创建超出 limits 的 Pod(预期失败)
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: over-limit-pod
  namespace: resource-demo
spec:
  containers:
  - name: big-container
    image: nginx
    resources:
      limits:
        cpu: "10"       # 超过 LimitRange 的 max.cpu: 2
        memory: "10Gi"
EOF

# 查看拒绝原因
oc describe pod over-limit-pod -n resource-demo

三、使用 NodeSelector 调度

NodeSelector 通过节点标签将 Pod 固定调度到满足条件的节点。


3.1 查看节点标签

# 查看所有节点及标签
oc get nodes --show-labels

# 以可读格式查看单个节点标签
oc describe node <node-name> | grep -A 20 "Labels:"

# 查看节点内置标签(常用)
oc get nodes -o custom-columns=\
NAME:.metadata.name,\
ROLE:.metadata.labels."node-role\.kubernetes\.io/worker",\
OS:.metadata.labels."kubernetes\.io/os",\
ARCH:.metadata.labels."kubernetes\.io/arch"

3.2 为节点添加自定义标签

# 语法:oc label node <node-name> <key>=<value>
oc label node worker-node-1 environment=production
oc label node worker-node-2 environment=staging
oc label node worker-node-1 disk=ssd

# 验证标签已添加
oc get node worker-node-1 --show-labels

# 删除标签(键后加 - 号)
# oc label node worker-node-1 disk-

3.3 在 Pod 中使用 NodeSelector

# nodeselector-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: prod-pod
  namespace: resource-demo
spec:
  nodeSelector:
    environment: production    # 只调度到有此标签的节点
    kubernetes.io/os: linux    # 可叠加多个标签(AND 逻辑)
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        cpu: "100m"
        memory: "64Mi"
      limits:
        cpu: "200m"
        memory: "128Mi"
oc apply -f nodeselector-pod.yaml

# 查看 Pod 被调度到哪个节点
oc get pod prod-pod -n resource-demo -o wide

# 确认节点选择器生效
oc describe pod prod-pod -n resource-demo | grep -A 3 "Node-Selectors"

3.4 在 Deployment 中使用 NodeSelector

# nodeselector-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prod-deployment
  namespace: resource-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: prod-app
  template:
    metadata:
      labels:
        app: prod-app
    spec:
      nodeSelector:
        environment: production   # 所有副本都调度到 production 节点
      containers:
      - name: app
        image: nginx:latest
        resources:
          requests:
            cpu: "100m"
            memory: "64Mi"
          limits:
            cpu: "300m"
            memory: "256Mi"
oc apply -f nodeselector-deployment.yaml

# 查看所有副本分布
oc get pods -l app=prod-app -n resource-demo -o wide

# 查看调度事件
oc get events -n resource-demo --sort-by='.lastTimestamp'

3.5 验证调度失败场景

# 设置一个不存在的标签(预期 Pod 进入 Pending 状态)
cat <<EOF | oc apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: unschedulable-pod
  namespace: resource-demo
spec:
  nodeSelector:
    environment: nonexistent   # 没有节点有此标签
  containers:
  - name: app
    image: nginx
EOF

# 观察 Pod 状态(应为 Pending)
oc get pod unschedulable-pod -n resource-demo

# 查看调度失败原因
oc describe pod unschedulable-pod -n resource-demo | grep -A 5 "Events:"

四、综合实践:资源限制 + NodeSelector

将两个特性结合,部署一个完整的生产级应用:

# combined-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: full-demo
  namespace: resource-demo
  labels:
    app: full-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: full-demo
  template:
    metadata:
      labels:
        app: full-demo
        tier: backend
    spec:
      # ---- NodeSelector ----
      nodeSelector:
        environment: production
        kubernetes.io/os: linux

      # ---- 容器定义 ----
      containers:
      - name: backend
        image: nginx:latest
        ports:
        - containerPort: 80
        # ---- 资源限制 ----
        resources:
          requests:
            cpu: "200m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "256Mi"
        # ---- 健康检查 ----
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 15
          periodSeconds: 20
oc apply -f combined-demo.yaml

# 全面验证
echo "=== Pod 状态 ==="
oc get pods -l app=full-demo -n resource-demo -o wide

echo "=== 资源使用 ==="
oc top pods -n resource-demo

echo "=== 节点选择器 ==="
oc describe pods -l app=full-demo -n resource-demo | grep -E "Node:|Node-Selectors:|Limits:|Requests:"

echo "=== 配额使用 ==="
oc describe resourcequota demo-quota -n resource-demo

五、常用诊断命令速查

# === 资源查看 ===
oc describe pod <pod-name>              # Pod 详情(含资源、事件)
oc top nodes                            # 节点资源使用率
oc top pods -n resource-demo           # Pod 资源使用率
oc get resourcequota -n resource-demo  # 查看配额
oc get limitrange -n resource-demo     # 查看限制范围

# === 节点标签管理 ===
oc get nodes --show-labels              # 查看所有节点标签
oc label node <node> key=value          # 添加标签
oc label node <node> key-               # 删除标签
oc get nodes -l key=value               # 按标签筛选节点

# === 调度诊断 ===
oc get events -n resource-demo --sort-by='.lastTimestamp'  # 查看事件
oc describe pod <pending-pod>           # 查看 Pending 原因

# === 清理实验环境 ===
oc delete project resource-demo

六、关键概念总结

概念 作用域 说明
resources.requests 容器 调度依据,保证最低资源
resources.limits 容器 资源使用上限
LimitRange 命名空间 设置默认值与单体上下限
ResourceQuota 命名空间 限制整个命名空间的总资源量
nodeSelector Pod/Deployment 按标签指定调度节点

💡 最佳实践:始终为生产环境的容器设置 requestslimits,并通过 LimitRange 为命名空间设置兜底默认值,防止未声明资源的 Pod 无限制地消耗集群资源。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐