1. Namespace命名空间:进程隔离的基石

Namespace(命名空间)是Linux内核提供的一种资源隔离机制,它通过将系统资源(如进程ID、网络、文件系统等)包装在独立的命名空间中,使得每个命名空间内的进程拥有独立的资源视图,从而实现进程间的隔离。这是Docker等容器技术实现轻量级虚拟化的核心基础。

在Linux系统中,每个进程的命名空间信息可以通过/proc/[pid]/ns/目录查看(使用echo $$可以显示当前Shell进程的PID)。内核共支持10种命名空间类型,每种类型负责隔离不同的系统资源。

1.1 Linux内核Namespace类型及作用对照表

软链接文件名命名空间类型核心作用说明
utsUTS Namespace隔离主机名、域名每个命名空间可独立设置hostname,容器互不干扰主机名称
pidPID Namespace隔离进程ID编号容器内进程PID从1重新计数,宿主机PID和容器内PID完全隔离;容器看不到宿主机其他进程
pid_for_childrenPID Namespace(子进程专用)新建子进程默认使用该PID命名空间和pid指向同一个编号,用于区分当前进程自身与后代进程的PID隔离环境
mount / mntMount Namespace隔离文件系统挂载视图每个命名空间拥有独立挂载列表,容器可自由挂载/卸载目录,不影响宿主机和其他容器
ipcIPC Namespace隔离进程间通信资源隔离System V信号量、消息队列、共享内存;不同命名空间进程无法通过IPC互相通信
netNetwork Namespace隔离网络协议栈独立网卡、IP地址、路由表、端口、防火墙规则;容器拥有独立网络环境
userUser Namespace隔离用户/用户组ID实现UID/GID映射:容器内root用户,在宿主机只是普通非特权用户,提升容器安全隔离
cgroupCgroup Namespace隔离cgroup控制组路径视图每个命名空间内看到的cgroup目录层级独立,进程无法跨命名空间操作外部cgroup限制
timeTime Namespace系统时钟隔离可单独修改容器内系统时间(CLOCK_REALTIME/CLOCK_MONOTONIC),不影响宿主机时间
time_for_childrenTime Namespace(子进程专用)新建子进程默认使用该时间命名空间与time指向同一编号,统一后代进程时钟隔离环境

1.2 补充说明

  • 路径来源:以上文件都位于进程目录/proc/$PID/ns/,每条lrwxrwxrwx软链接指向内核命名空间唯一句柄类型:[编号];
  • 容器基础:Docker、Podman、LXC等容器技术全部基于以上Namespace实现资源隔离;
  • 权限:默认归属root,普通用户无法直接修改命名空间隔离视图。

2. Cgroups控制组:资源限制的核心机制

Cgroups(Control Groups,控制组)是Linux内核提供的资源隔离与限制技术,用于限制容器使用的一组资源,包括CPU、内存、网络带宽、磁盘读写等。它是Docker等容器技术实现资源配额管理的核心组件。

2.1 什么是Cgroups

Cgroups(Control Groups,控制组)是Linux内核提供的资源隔离与限制技术,核心作用:

  1. 资源限制:限制进程组使用CPU、内存、IO、网络等硬件资源上限;
  2. 资源统计:统计进程组资源消耗(CPU时长、内存占用、磁盘读写等);
  3. 资源优先级:给不同进程组分配权重,调度优先顺序;
  4. 进程隔离:将一组进程打包管理,配合Namespace实现容器(Docker/K8s)基础隔离;
  5. 进程冻结/销毁:批量暂停、杀死一组进程。
核心组件
  1. subsystem(子系统):对应一类资源控制器
    • cpu:CPU使用率、调度权重限制
    • cpuacct:CPU使用统计
    • cpuset:绑定进程到指定CPU核心/NUMA节点
    • memory:内存、Swap限制,OOM控制
    • blkio:块设备磁盘IO限速、权重
    • devices:管控进程能访问哪些硬件设备
    • net_cls/net_prio:网络流量标记、网络优先级
    • pid:限制组内最大进程数量
    • hugetlb:大页内存资源限制
  2. hierarchy(层级树):cgroup树形结构,父组资源限制会传递约束子组;
  3. cgroup组:树中的节点,绑定子系统,挂载在文件系统;
  4. tasks:文件记录该组所有进程PID,将进程加入cgroup只需写入PID。

2.2 Cgroups两大版本:v1与v2

2.2.1 Cgroups v1(传统版本,CentOS7、老Docker默认)

特点:

  • 多层级分离挂载:每个资源子系统独立挂载一个文件系统目录(/sys/fs/cgroup/cpu、/sys/fs/cgroup/memory分开);
  • 一个进程可以同时存在于多个不同层级的cgroup,管理逻辑割裂;
  • 控制器分散,统一资源管控复杂,存在资源竞争漏洞;
  • 兼容所有老内核,生产环境存量极多。

典型目录结构:

/sys/fs/cgroup/
├── cpu/
├── memory/
├── blkio/
├── pid/
└── cpuset/
2.2.2 Cgroups v2(统一层级,现代标准,内核4.5+推荐,K8s 1.24+默认)

核心改进:

  • 统一单一层级:所有资源控制器挂载在同一个根目录/sys/fs/cgroup/unified,所有子系统统一管理;
  • 进程只能属于一个cgroup节点,层级逻辑清晰;
  • 统一接口规范,修复v1资源逃逸、限制失效问题;
  • 支持精细化内存压力、IO压力监控;
  • systemd、containerd、runc全面支持,云原生标准。

启用条件:内核版本≥4.5,内核开启CONFIG_CGROUP2,启动参数添加systemd.unified_cgroup_hierarchy=1。

2.2.3 v1 vs v2对比表
特性cgroups v1cgroups v2
挂载结构多独立层级单一统一层级
进程归属可跨多个组仅归属一个组
控制器接口每个子系统文件不同标准化统一文件
内存/CPU协同限制容易失效协同管控更可靠
云原生支持兼容,逐步淘汰K8s、Docker推荐默认
内核要求2.6.24+4.5+

2.3 Cgroups使用案例(分原生手动操作+生产容器场景)

案例1:手动cgroups v1限制进程内存(原生命令操作)

环境:CentOS7,自带cgroup v1,无需额外安装工具。

步骤1:进入内存子系统挂载目录

cd /sys/fs/cgroup/memory
# 创建名为limit_mem的控制组,自动生成配置文件
mkdir limit_mem
cd limit_mem

步骤2:设置内存上限(限制最大512M内存+512M swap)

# 单位字节,512M = 536870912
echo 536870912 > memory.limit_in_bytes
echo 536870912 > memory.memsw.limit_in_bytes
# 开启OOM,内存超限直接杀死进程
echo 1 > memory.oom_control

步骤3:把目标进程加入该cgroup

# 将PID=1234的进程放入限制组
echo 1234 > tasks

此时进程1234内存超过512M会被系统OOM杀死。

案例2:cgroups v1限制CPU使用率
cd /sys/fs/cgroup/cpu
mkdir limit_cpu
cd limit_cpu
# cpu.cfs_quota_us:周期内最大可用CPU时间,周期默认100000微秒
# 限制单核CPU最多使用20%:20000 / 100000 = 20%
echo 20000 > cpu.cfs_quota_us
echo 100000 > cpu.cfs_period_us
# 加入进程
echo 1234 > tasks
案例3:cgroups v2统一层级限制内存+CPU(现代系统Ubuntu22/CentOS9)

1. 确认v2已启用

mount | grep cgroup2
# 输出 /sys/fs/cgroup/unified type cgroup2 代表启用成功

2. 创建控制组

cd /sys/fs/cgroup/unified
mkdir app_server
cd app_server

3. 启用需要的控制器(v2必须手动开启控制器)

echo "+cpu +memory" > cgroup.controllers

4. 设置资源限制

# CPU限制:单CPU 30% (max 30000 周期100000)
echo "30000 100000" > cpu.max
# 内存限制 1G
echo 1G > memory.max

5. 加入进程

echo 1234 > cgroup.procs
案例4:systemd管理cgroup(最常用生产方式,无需手动操作文件)

systemd自动基于cgroups管理服务,每个service对应独立cgroup,配置直接写service文件。

示例:限制nginx服务CPU 20%、内存512M

编辑/etc/systemd/system/nginx.service添加:

[Service]
# CPU限额
CPUQuota=20%
# 内存上限
MemoryMax=512M
# 最大进程数
TasksMax=50
# IO读写限速
IOReadBandwidthMax=/dev/sda 10M

重载生效:

systemctl daemon-reload
systemctl restart nginx

systemd底层自动操作cgroups v1/v2,屏蔽底层文件操作,企业服务器广泛使用。

案例5:容器场景(Docker/K8s,cgroups最大落地场景)

容器 = Namespace(隔离视图)+ Cgroups(限制资源)+ rootfs(文件系统)

1. Docker使用cgroups

# 启动容器,限制1核CPU、512M内存,底层自动创建cgroup
docker run -it --memory=512m --cpus=1 nginx
  • Docker会自动在/sys/fs/cgroup/创建专属容器cgroup目录;
  • 容器内所有进程PID全部写入该cgroup的tasks,实现资源硬限制;
  • 内存打满直接OOM,CPU无法超限抢占宿主机资源。

2. Kubernetes使用cgroups v2

K8s 1.24默认使用cgroup v2,通过resources.limits定义资源约束:

resources:
  limits:
    cpu: "500m" # 0.5核
    memory: 512Mi

kubelet + containerd/runc负责创建、管理Pod专属cgroup,保障节点资源不被单个Pod耗尽。

案例6:离线业务资源隔离(服务器多业务混部)

一台物理机同时部署数据库、web服务、定时任务:

  1. 数据库:高优先级,分配80% CPU权重,8G内存;
  2. Web服务:常规,40% CPU权重,4G内存;
  3. 定时脚本:低优先级,限制10% CPU,1G内存;

通过cgroups cpuset将数据库绑定到大核CPU,memory限制各业务内存,避免定时任务抢占数据库资源,实现服务器混部资源隔离,降低硬件采购成本。

案例7:限制进程最大PID,防止fork炸弹

使用pid子系统限制组内进程总数,防御fork炸弹:

# v1操作
cd /sys/fs/cgroup/pid
mkdir safe_task
echo 100 > pid.max
echo 进程PID > tasks

组内最多创建100个进程,恶意fork会直接失败。

2.4 补充关键知识点

  1. 查看系统是否开启cgroup
    # 查看内核配置
    zcat /proc/config.gz | grep CGROUP
    # 查看已挂载cgroup
    ls /sys/fs/cgroup/
  2. 主流工具
    • 手动:直接读写/sys/fs/cgroup文件;
    • systemd:系统服务自动管理;
    • libcgroup:工具包cgcreate/cgset/cgexec简化操作;
    • runc/containerd/docker:容器运行时封装cgroup;
    • kubelet:编排平

更多推荐