通过 `cpuset` 将容器绑定到指定物理核

解读

在国内一线互联网与金融云原生面试中,**“容器绑核”**是高频考点。
面试官真正想验证的是:

  1. 你是否理解 Linux Cgroup 子系统 cpuset 的调度原理;
  2. 能否在 生产多 NUMA 节点 场景下,既保证业务性能又避免 跨 NUMA 抢占
  3. 是否具备 镜像层、编排层、宿主机层 的闭环意识,能把“绑核”做成可灰度、可回滚、可监控的交付方案。
    回答时切忌只背命令,而要给出 “为什么、怎么做、怎么验、怎么兜底” 四段式闭环。

知识点

  • Cgroup v1/v2 的 cpuset 控制器差异:v1 需要挂载 cpuset 子系统,v2 统一在 unified 层级;Docker 20.10+ 已默认兼容。
  • CPU 编号规则:宿主机 lscpu -e 看到的 CPU 列即为物理核号;超线程场景下 0,1 可能是同一物理核的两个线程,绑核需 关闭超线程成对绑定以避免抖动。
  • NUMA 亲和cpuset.cpuscpuset.mems 必须同时设置,否则容器可能在 Node0 上运行却访问 Node1 内存,延迟飙升。
  • Docker 三种写法
    1. docker run --cpuset-cpus="4-7"
    2. compose v3.8 的 deploy.resources.limits.cpus: '4-7'(仅 Swarm 生效)
    3. K8s 的 resources.limits.cpu: 4 配合 static CPU Manager policy 实现独占。
  • 热更新限制cpuset 属于 不可在线修改 的 cgroup,容器启动后调核必须重建 Pod,灰度时要 双版本滚动
  • 监控与兜底:通过 cAdvisorcontainer_spec_cpu_idnode_cpu_seconds_total{cpu="4"} 交叉验证;同时给容器加 --cpu-shares 保底,防止绑核失败时进程被完全饿死。

答案

步骤 1:宿主机前置检查

lscpu -e | awk '{print $1}' | grep -E '^[0-9]+$' | sort -n | uniq > /tmp/avail.list
numactl --hardware | grep -E 'node [0-9] cpus'

确认目标核 4-7 属于同一 NUMA node,且未被宿主机 isolcpus 隔离。

步骤 2:启动容器并绑核

docker run -d --name order-service \
  --cpuset-cpus="4-7" \
  --cpuset-mems="0" \
  --memory="8g" \
  --cpu-shares=1024 \
  myharbor.example.com/orders:v1.3.0

解释:

  • 双参数同时出现 才能确保 CPU 与内存同 node;
  • --cpu-shares 作为 兜底策略,防止 cpuset 异常时进程被彻底压制;
  • 镜像地址使用 内网 Harbor 域名,符合国内金融公司强制 私有镜像仓库 合规要求。

步骤 3:验证

docker exec order-service cat /sys/fs/cgroup/cpuset/cpuset.cpus
# 输出 4-7 为成功
docker exec order-service taskset -c -p 1
# 确认主进程 1 号只在 4-7 上调度

宿主机侧通过 top -p $(docker inspect -f '{{.State.Pid}}' order-service) 再按 1 键,观察 仅 4-7 核的 %CPU 上涨,其余核为 0%,即完成交叉验证。

步骤 4:编排层固化
Swarm 场景写入 compose 文件:

deploy:
  replicas: 3
  resources:
    limits:
      cpus: '4-7'
      memory: 8G
    reservations:
      cpus: '4-7'
      memory: 8G

K8s 场景开启 Kubelet static CPU Manager 并给 Pod 加 Guaranteed QoS,即可由 kubelet 自动写入 cpuset

步骤 5:灰度与回滚
利用 蓝绿标签

docker run --label version=blue ...

通过 SLB 权重 把 5% 流量导入蓝组,观察 P99 延迟下降 ≥8% 且无 NUMA 跨节点内存增长,则全量切流;否则 docker rm 蓝组容器即可秒级回滚。

拓展思考

  1. 超线程与物理核隔离
    国内头部券商容器云采用 BIOS 关闭超线程 方案,避免 cpu0/1 逻辑核对同一物理核的争抢;若无法关 HT,需使用 taskset -c 0,2,4,6 仅绑偶数核,确保 一核一线程

  2. 混部场景下的动态绑核
    阿里内部使用 Koordinator + NRI 在离线混部,实时根据在线负载 动态调整 cpuset;Docker 单机会话无法热更新,需通过 重建容器 + checkpoint/restore 技术实现亚秒级切换,面试可提此思路体现深度。

  3. 安全与合规
    央行《金融容器规范》要求 容器不得跨越宿主机 CPU 配额,绑核后需通过 auditd 监控 /sys/fs/cgroup/cpuset 的写入事件,防止恶意进程通过 docker exec 篡改;可封装 OPA Gatekeeper 策略 拒绝提交含非法 cpuset-cpus 的 Pod。

  4. 与 CPU Quota 的权衡
    绑核放弃弹性,CPU 利用率可能降至 30%;可引入 潮汐混部:白天绑核保障交易延迟,夜间解除绑核运行大数据离线任务,通过 定时修改 deployment 注解 触发重建,实现 “同集群不同策略” 的精细化运营。