Shell脚本如何配置容器资源超卖

wen 实用脚本 3

本文目录导读:

Shell脚本如何配置容器资源超卖

  1. Docker 运行时(最常见)
  2. Kubernetes 场景(通过 Shell 调度 Pod)
  3. 容器运行时底层(cgroups v2 直接操作)
  4. 关键注意事项

在Shell脚本中配置容器资源超卖,主要涉及调整CPU内存的限制参数,不同容器运行时(Docker、Podman、containerd)和底层资源管理的实现方式不同。

核心思路是:设置高于实际物理资源总量的 limits(上限),或设置较低的 requests(预留)+ 较高的 limits,让调度器认为有更多资源可用。

以下是针对常见场景的Shell脚本配置方法:

Docker 运行时(最常见)

Docker 通过 --cpu-shares(相对权重)、--cpus(绝对限制)和 --memory--memory-swap 参数实现超卖。

场景:物理机 4核CPU,8GB内存,想跑 8个容器

Shell脚本示例(超卖 CPU 和 内存):

#!/bin/bash
# 容器配置
CONTAINER_IMAGE="nginx:alpine"
CONTAINER_COUNT=8
NETWORK_NAME="my_overlay"
# 每个容器申请的资源(超卖配置)
# CPU:使用 shares(权重),让 8 个容器在 4 核上竞争
# 内存:设置硬限制,但 swap 开高,实际可超卖
CPU_SHARES="1024"           # 默认1024,8个容器总和=8192 > 4核理论值
MEMORY_LIMIT="1g"           # 每个容器最大1GB
MEMORY_SWAP="2g"            # 允许使用swap,变相超卖内存
MEMORY_RESERVATION="512m"   # 软限制,保证基础
# 创建网络(如果不存在)
docker network inspect $NETWORK_NAME >/dev/null 2>&1 || docker network create $NETWORK_NAME
# 启动容器实现超卖
for i in $(seq 1 $CONTAINER_COUNT); do
    echo "Starting container web-$i with oversubscription..."
    docker run -d \
        --name "web-$i" \
        --network $NETWORK_NAME \
        --cpus "0.5" \                # 每个容器限制0.5核,8个总共4核(物理100%)
        --cpu-shares $CPU_SHARES \    # 相对权重,所有容器均等
        --memory $MEMORY_LIMIT \      # 硬限制1GB
        --memory-swap $MEMORY_SWAP \  # swap空间,允许内存超卖
        --memory-reservation $MEMORY_RESERVATION \ # 软限制512MB
        $CONTAINER_IMAGE
done
echo "8 containers started with CPU oversubscription (8 * 0.5 = 4 cores) and memory oversubscription (8 * 1GB = 8GB total, swap enabled)."

关键参数说明:

  • --cpus:限制容器使用的 CPU 核心数(可以是非整数,如 5)。
    超卖技巧: --cpus 总和可超过物理核心数,如 4 核机器,--cpus 0.5 * 10 = 5 核
  • --cpu-shares:默认 1024,所有容器按权重分配 CPU 时间。
    超卖技巧: 设置较低值(如 512)让容器被视为“低优先级”,但允许大量容器共存。
  • --memory:硬限制容器内存使用上限。
  • --memory-swap:等于 memory + swap 总量,设为 -1 则不限 swap。
    超卖技巧: --memory-swap > --memory 允许使用 swap,从而运行超过物理内存的容器。
  • --memory-reservation:软限制,只在内存紧张时生效。

Kubernetes 场景(通过 Shell 调度 Pod)

在 Kubernetes 中,超卖通过 ResourceQuotaLimitRange 实现,Shell 脚本通常用于创建这些对象。

场景:在 4核16GB 的 Node 上部署大量测试 Pod

Shell脚本示例(创建超卖策略):

#!/bin/bash
NAMESPACE="oversubscription-demo"
# 1. 创建命名空间
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
# 2. 创建 LimitRange(默认限制,让没设置的Pod自动拥有超卖配置)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
  name: oversubscription-limit
  namespace: $NAMESPACE
spec:
  limits:
  - default:
      cpu: "1"            # 默认 limits CPU = 1核
      memory: "512Mi"     # 默认 limits 内存 = 512MB
    defaultRequest:
      cpu: "0.1"          # 默认 requests CPU = 0.1核(超卖关键!)
      memory: "128Mi"     # 默认 requests 内存 = 128MB
    type: Container
EOF
# 3. 批量创建 Deployment(每个 Pod 将继承 LimitRange 的超卖配置)
for i in {1..20}; do
  cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-$i
  namespace: $NAMESPACE
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-$i
  template:
    metadata:
      labels:
        app: app-$i
    spec:
      containers:
      - name: app
        image: nginx:alpine
        # 注意:没有显式设置 resources,将使用 LimitRange 默认值
EOF
done
echo "Created 20 pods with oversubscription: each requests 0.1 CPU, limits 1 CPU (10x oversubscription)."

关键点:

  • requests vs limits
    • requests 低(0.1核)→ 调度器认为可用资源多。
    • limits 高(1核)→ 容器运行时可在空闲时使用更多CPU。
      超卖比例: limits / requests = 10:1(10倍超卖)。
  • LimitRange 确保所有 Pod 自动获得超卖配置,无需修改 YAML。

容器运行时底层(cgroups v2 直接操作)

如果使用 containerd 或直接管理 cgroups(如系统容器),Shell 脚本可以直接写入 cgroup 文件。

Shell示例(cgroups v2 直接超卖):

#!/bin/bash
# 假设容器 PID 为 $PID,cgroup 路径为 /sys/fs/cgroup/system.slice/containerd-xxx.scope
CGROUP_PATH="/sys/fs/cgroup/system.slice/docker-xxxxxxxx.scope"
# CPU 超卖:设置 cpu.weight(类似 cpu-shares)
# 所有容器权重之和 > 10000 即超卖
echo "2048" > $CGROUP_PATH/cpu.weight  # 每个容器给 2048
# 内存超卖:设置 memory.max(硬限制)
echo "1G" > $CGROUP_PATH/memory.max    # 硬限制 1GB
echo "2G" > $CGROUP_PATH/memory.swap.max  # 允许 2GB swap
# 禁用 OOM killer(内存超卖时避免被杀)
echo "0" > $CGROUP_PATH/memory.oom.group  # 0 = 禁用组 OOM

关键注意事项

  1. 物理资源限制:
    CPU 超卖通常安全(等待调度),但内存超卖可能导致 OOM Killer 或 Swap 风暴,建议用 swappiness=0 避免系统卡死:

    echo "0" > /proc/sys/vm/swappiness
  2. 监控与驱逐:
    超卖环境中必须配置监控,避免资源耗尽,Docker Compose 可加 deploy.resources.limits;K8s 需配置 Vertical Pod Autoscaler 或第三方程控。

  3. 负载类型:

    • CPU密集型:超卖比例不超过 2:1(否则响应变慢)。
    • 内存空闲型:可 5:1 或更高(适合静态文件服务)。
  4. 测试脚本:
    使用 stress 工具模拟负载,验证超卖效果:

    docker run --rm --cpus 0.5 --memory 256m progrium/stress --cpu 2 --vm 1 --vm-bytes 128M
运行时 超卖方法 Shell 关键参数
Docker --cpu-shares / --cpus + --memory-swap --cpus 0.5 --cpu-shares 1024 --memory 1g --memory-swap 2g
K8s 设置低 requests + 高 limits 通过 LimitRange 或直接在 YAML 中设置 resources.requests
直接 cgroups 写入 cpu.weightmemory.maxmemory.swap.max 直接修改 /sys/fs/cgroup/... 文件

最佳实践:

  1. 生产环境不建议过度超卖(CPU < 3x,内存 < 1.5x)。
  2. 测试环境可大胆超卖(CPU 10x,内存 3x)。
  3. 始终给核心服务(数据库、K8s 控制面)保留专用资源,不参与超卖。

抱歉,评论功能暂时关闭!