Kubespray 如何用 kube_reserved 与 system_reserved cgroups 限制守护进程与 Pod 的资源争抢?
【免费下载链接】kubesprayDeploy a Production Ready Kubernetes Cluster项目地址: https://gitcode.com/GitHub_Trending/ku/kubespray
在自建 Kubernetes 集群的节点上,kubelet、容器运行时守护进程(containerd、Docker、CRI-O 或 cri-dockerd)与业务 Pod 共享同一台机器的 CPU 和内存,任何一方的突发消耗都可能拖累另一方。Kubespray 通过kube_reserved与system_reserved两个开关,把这些守护进程放进专用 cgroup 并为其预留资源,再配合kubelet_enforce_node_allocatable让 kubelet 按预留量强制管控节点可分配资源,从而降低守护进程与 Pod 之间的资源争抢。
本文面向已经用 Kubespray 部署集群、想控制节点资源争用的运维者,说明如何配置这些变量、Kubespray 在节点上实际生成什么配置,以及按文档给出的层级结构如何确认生效。
先分清:预留资源 ≠ 限制用量
Kubespray 的 cgroups 文档 明确区分了两件事:
- 资源预留(
kube_memory_reserved、kube_cpu_reserved等):只让 kubelet 在计算可分配资源时扣掉这部分量,不限制守护进程实际能用多少; - 限制用量:需要把 kubelet 和容器引擎守护进程放进专用 cgroup,即设置
kube_reserved: true。
文档原文说明:
Set kube_reserved to true to run kubelet and container-engine daemons in a dedicated cgroup. This is required if you want to enforce limits on the resource usage of these daemons. It is not required if you just want to make resource reservations.
默认值在 roles/kubernetes/node/defaults/main.yml 中:kube_reserved: false、system_reserved: false,kubelet_enforce_node_allocatable默认为空(不强制任何级别)。预留类变量已有默认值:kube_memory_reserved: "256Mi"、kube_cpu_reserved: "100m"、kube_ephemeral_storage_reserved: "500Mi"、kube_pid_reserved: "1000";系统侧为system_memory_reserved: "512Mi"、system_cpu_reserved: "500m"、system_ephemeral_storage_reserved: "500Mi"、system_pid_reserved: 1000。
还有一个关键约束:要让 kubelet 强制kube-reserved或system-reserved级别,必须分别指定kube_reserved_cgroups或system_reserved_cgroups。
配置:在 inventory 的 group_vars 中覆盖变量
把文档示例中的配置放进你的 inventory 的 group_vars(注释版写法可参考 inventory/sample/group_vars/k8s_cluster/k8s-cluster.yml 中 "Reserve this space for kube resources" 与 "Optionally reserve resources for OS system daemons" 两段):
kubelet_enforce_node_allocatable: "pods,kube-reserved,system-reserved" # Set kube_reserved to true to run kubelet and container-engine daemons in a dedicated cgroup. # This is required if you want to enforce limits on the resource usage of these daemons. # It is not required if you just want to make resource reservations (kube_memory_reserved, kube_cpu_reserved, etc.) kube_reserved: true kube_reserved_cgroups_for_service_slice: kube.slice kube_reserved_cgroups: "/{{ kube_reserved_cgroups_for_service_slice }}" kube_memory_reserved: 256Mi kube_cpu_reserved: 100m # kube_ephemeral_storage_reserved: 2Gi # kube_pid_reserved: "1000" # Set to true to reserve resources for system daemons system_reserved: true system_reserved_cgroups_for_service_slice: system.slice system_reserved_cgroups: "/{{ system_reserved_cgroups_for_service_slice }}" system_memory_reserved: 512Mi system_cpu_reserved: 500m # system_ephemeral_storage_reserved: 2Gi # system_pid_reserved: "1000"几点说明:
kubelet_enforce_node_allocatable是逗号分隔的强制级别列表,可选值为pods、kube-reserved、system-reserved(空值表示不强制)。只要列表里出现kube-reserved或system-reserved,对应的*_reserved_cgroups必须已指定。- 代码块中的
{{ kube_reserved_cgroups_for_service_slice }}、{{ system_reserved_cgroups_for_service_slice }}不是需要手工替换的占位符,而是 Ansible 变量表达式,部署时解析为上面定义的kube.slice/system.slice。默认变量文件中kube_reserved_cgroups与system_reserved_cgroups已是同样表达式,文档示例把它们显式写出是为了满足"必须指定"这一约束。 256Mi、100m、512Mi、500m是文档示例值,应按节点规格自行调整,不要照抄。
Kubespray 在节点上实际生成什么
这些变量最终落到三类文件上,理解它们有助于验证和排查:
- kubelet 单元文件roles/kubernetes/node/templates/kubelet.service.j2:当
kube_reserved或system_reserved为 true 时,生成一组ExecStartPre=/bin/mkdir -p /sys/fs/cgroup/{cpu,cpuacct,cpuset,hugetlb,memory,pids,systemd}/<slice>,为对应 slice 预建 cgroup 目录。 - 容器引擎单元/配置:containerd(containerd.service.j2)、Docker(docker.service.j2)、cri-dockerd(cri-dockerd.service.j2)在
kube_reserved: true时写入Slice={{ kube_reserved_cgroups_for_service_slice }},把守护进程 systemd 单元挂到kube.slice下;CRI-O 则在 crio.conf.j2 中写入conmon_cgroup = "{{ kube_reserved_cgroups_for_service_slice }}"。 - kubelet 配置文件roles/kubernetes/node/templates/kubelet-config.v1beta1.yaml.j2:当
kubelet_enforce_node_allocatable非默认空值时,按逗号拆分并写入enforceNodeAllocatable列表。
执行:用 cluster.yml 应用变更
配置写入 inventory 后,按 README 给出的方式对现有集群执行cluster.yml即可下发变更(其中 inventory 路径与私钥路径按你的实际环境替换):
ansible-playbook -i /inventory/inventory.ini --private-key /root/.ssh/id_rsa cluster.yml该 playbook 会重新渲染上述模板并重启相关单元,使新的 cgroup 归属与 kubelet 配置在节点上生效。
验证:对照文档中的 cgroup 层级
docs/operations/cgroups.md 给出配置成功后的 cgroup 层级(文档示例):
/ (Cgroups Root) ├── kubepods.slice │ ├── ... │ ├── kubepods-besteffort.slice │ ├── kubepods-burstable.slice │ └── ... ├── kube.slice │ ├── ... │ ├── {{container_manager}}.service │ ├── kubelet.service │ └── ... ├── system.slice │ └── ... └── ...其中{{container_manager}}是你的容器运行时名称(默认为containerd)。判断方法:在节点上查看 cgroup 树(如/sys/fs/cgroup下的各 slice 目录),确认kube.slice下出现容器运行时与kubelet.service,Pod 负载位于kubepods.slice,操作系统守护进程位于system.slice。如果守护进程仍在system.slice内或层级与示例不符,说明对应的*_reserved开关或 cgroup 变量没有真正生效,应回查 inventory 覆盖值与单元文件是否重新渲染。
限制与边界
- 只做资源预留(设置
kube_memory_reserved等)而不打开kube_reserved/system_reserved,不会限制守护进程实际用量,两者预期不要混淆。 kubelet_enforce_node_allocatable默认为空,即不强制任何级别;启用后节点可分配资源会按预留量扣减,直接影响调度结果。- 若要启用 CPU 静态管理策略(
kubelet_cpu_manager_policy: static),docs/ansible/vars.md 指出它需要与kube_reserved或system-reserved配合,本文的 cgroup 配置正是该前提的一部分。 - 驱逐阈值(
eviction_hard,默认{})与官方 "Reserve compute resources" 文档属于同一主题的延伸内容,本文不展开。
【免费下载链接】kubesprayDeploy a Production Ready Kubernetes Cluster项目地址: https://gitcode.com/GitHub_Trending/ku/kubespray
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考