AI 算力基础设施深度系列(一):从容器到 Kubernetes——算力底座的诞生

AI 算力基础设施深度系列(一):从容器到 Kubernetes——算力底座的诞生

本文是《AI 算力基础设施深度系列》第 1 篇,共 6 篇。
系列目录:① 容器与 K8S 基础 → ② K8S 底层原理 → ③ GPU 与异构算力 → ④ AI 平台架构 → ⑤ 高性能网络与存储 → ⑥ 生产运维与成本优化

导语

2024 年底,OpenAI 公开了一个让基础设施工程师集体沉默的数字:他们在 Kubernetes 上编排了 25,000 块 GPU,支撑 GPT 系列模型的训练和推理。 同一时间,Google GKE 宣布单集群支持 65,000 个节点,阿里云 ACK 已经在内部支撑了数以万计的 AI 训练任务。

一件事已经很清楚了:Kubernetes 不再只是"跑微服务的编排器"——它正在成为 AI 时代的算力操作系统。

但在理解 Kubernetes 如何管理 GPU、如何编排分布式训练之前,我们需要先回答一个更基础的问题:Kubernetes 是什么?它为什么能成为 AI 算力的底座?

这个问题看似简单,但如果你不理解容器技术的本质、不理解 Kubernetes 的核心设计哲学,后面所有关于 GPU 调度、拓扑感知、Gang 调度的讨论都会变成空中楼阁。

本文是整个系列的起点。我们将从最基础的问题出发:计算资源是怎么被隔离和管理的? 从物理机到虚拟机,从虚拟机到容器,从单机容器到 Kubernetes 集群——每一步演进都在解决什么问题?最终,我们会带着这些理解,看看为什么 AI 算力场景对 Kubernetes 提出了全新的挑战。


一、计算资源的隔离演进:从物理机到容器

1.1 物理机时代:一台机器一个应用

最初的服务器部署模式很直接:一台物理机跑一个应用

┌─────────────────────────────────┐
│            应用 A                │
├─────────────────────────────────┤
│        操作系统 (Linux)          │
├─────────────────────────────────┤
│    硬件 (CPU / 内存 / 磁盘)      │
└─────────────────────────────────┘

问题显而易见:

  • 资源浪费:一个 Web 应用可能只用了 10% 的 CPU,剩余 90% 闲置
  • 扩展困难:想部署新应用?买台新服务器
  • 环境冲突:两个应用依赖同一个库的不同版本,放在一台机器上必出问题

1.2 虚拟机时代:一台机器多个"逻辑机器"

虚拟化技术(VMware、KVM、Xen)解决了物理机的资源浪费问题。通过 Hypervisor 在一台物理机上虚拟出多台"逻辑机器",每台虚拟机拥有独立的操作系统、独立的内核、独立的资源空间。

┌──────────┐  ┌──────────┐  ┌──────────┐
│  App A   │  │  App B   │  │  App C   │
├──────────┤  ├──────────┤  ├──────────┤
│ Guest OS │  │ Guest OS │  │ Guest OS │
│ (Ubuntu) │  │ (CentOS) │  │ (Debian) │
└────┬─────┘  └────┬─────┘  └────┬─────┘
     └──────┬──────┘──────┬──────┘
     ┌──────▼─────────────▼──────┐
     │       Hypervisor           │
     │    (KVM / VMware ESXi)     │
     ├───────────────────────────┤
     │      Host OS (Linux)       │
     ├───────────────────────────┤
     │   硬件 (CPU / 内存 / 磁盘)  │
     └───────────────────────────┘

优点:强隔离——每个虚拟机有独立内核,一个虚拟机崩溃不影响其他虚拟机。

致命缺点

  • :每个虚拟机都需要运行完整的 Guest OS,占用 GB 级内存
  • :启动一个虚拟机需要分钟级时间
  • 开销大:Hypervisor 本身消耗 5-15% 的 CPU,内存虚拟化也有损耗

当你需要在一台 8 卡 GPU 服务器上同时跑 20 个推理任务时,每个任务都启动一个完整的虚拟机?光是 Guest OS 就要吃掉几十 GB 内存。

1.3 容器时代:同一个内核,不同的视图

容器的核心洞察是:大多数应用并不需要独立的操作系统内核,它们需要的只是一个"看起来"独立的运行环境。

容器不虚拟硬件,也不运行 Guest OS。它直接运行在宿主机内核之上,通过 Linux 内核的三大机制实现"隔离的假象":

┌──────────┐  ┌──────────┐  ┌──────────┐
│  App A   │  │  App B   │  │  App C   │
│ (容器)    │  │ (容器)    │  │ (容器)    │
├──────────┤  ├──────────┤  ├──────────┤
│ Libs/Bins│  │ Libs/Bins│  │ Libs/Bins│
└────┬─────┘  └────┬─────┘  └────┬─────┘
     └──────┬──────┘──────┬──────┘
     ┌──────▼─────────────▼──────┐
     │    Container Runtime       │
     │  (containerd / CRI-O)      │
     ├───────────────────────────┤
     │    Host OS Kernel (Linux)  │  ← 共享同一个内核!
     ├───────────────────────────┤
     │   硬件 (CPU / 内存 / 磁盘)  │
     └───────────────────────────┘

对比总结

维度 物理机 虚拟机 容器
隔离级别 物理隔离 硬件虚拟化 OS 级(进程隔离)
启动速度 分钟级 30秒-数分钟 毫秒-秒级
资源开销 无额外开销 GB 级(Guest OS) MB 级(仅应用+依赖)
密度 1 应用/机器 数十 VM/机器 数百容器/机器
内核 独占 独立 Guest 内核 共享宿主机内核
性能 原生 有损(5-15%) 接近原生(<2%)

容器就是"用内核的视图隔离能力,以接近零开销的方式,把一个进程封装成一个独立的运行单元。"

这对 AI 场景意味着什么?一块 H100 GPU 价值 3 万美元,你不会愿意为每个推理任务分配一整台虚拟机的开销。容器让你可以在同一台 GPU 服务器上高密度部署几十个推理服务,几乎零开销地共享底层算力


二、容器核心技术三件套:Namespace、Cgroup、Union FS

容器不是一个魔法黑盒。它本质上就是一个 受约束的 Linux 进程,通过三个内核机制实现隔离:

  • Namespace:让进程"看到"一个独立的世界(视图隔离)
  • Cgroup:限制进程能"使用"多少资源(资源限制)
  • Union FS:让进程有自己的"文件系统"(镜像分层)

2.1 Linux Namespace:给进程戴上"VR 眼镜"

Namespace 是 Linux 内核提供的资源隔离机制。每个 Namespace 为进程组创建一个"独立的视图"——进程在 Namespace 内看到的世界与宿主机不同。

Linux 支持 8 种 Namespace

Namespace 隔离内容 系统调用标志 引入版本
Mount (mnt) 文件系统挂载点 CLONE_NEWNS Linux 2.4.19
UTS 主机名和域名 CLONE_NEWUTS Linux 2.6.19
IPC 进程间通信资源 CLONE_NEWIPC Linux 2.6.19
PID 进程 ID 空间 CLONE_NEWPID Linux 2.6.24
Network (net) 网络设备、IP、端口、路由 CLONE_NEWNET Linux 2.6.29
User 用户和用户组 ID CLONE_NEWUSER Linux 3.8
Cgroup Cgroup 根目录视图 CLONE_NEWCGROUP Linux 4.6
Time 系统时钟 CLONE_NEWTIME Linux 5.6

一个直观的例子:PID Namespace

在宿主机上,所有进程共享同一个 PID 空间,init 进程是 PID 1。当你创建一个新的 PID Namespace 时,这个 Namespace 内的第一个进程会被编号为 PID 1——它认为自己是 init,完全看不到 Namespace 外的进程。

宿主机视角:
  PID 1    (systemd)
  PID 1234 (containerd)
  PID 5678 (容器内的 nginx)     ← 宿主机看到的真实 PID

容器内视角 (PID Namespace):
  PID 1    (nginx)              ← 容器内看到的 PID,它认为自己是 init
  PID 2    (nginx worker)
  (看不到任何宿主机进程)

Network Namespace 对 AI 场景尤其重要

每个 Network Namespace 有独立的网络栈——IP 地址、路由表、iptables 规则、网络设备。这意味着:

  • 每个容器可以有自己的 IP 地址(不用端口映射)
  • 容器间的网络通信需要通过虚拟网络设备(veth pair)桥接
  • 后续的 RDMA 网络直通、GPUDirect 等高性能网络方案,本质上就是在绕过或优化 Network Namespace 带来的网络栈开销

创建 Namespace 的底层 API

// 方式一:通过 clone() 系统调用创建新进程时指定 Namespace
int pid = clone(child_func, child_stack + STACK_SIZE,
                CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWNS | SIGCHLD,
                NULL);

// 方式二:通过 unshare() 让当前进程进入新的 Namespace
unshare(CLONE_NEWPID | CLONE_NEWNET);

// 方式三:通过 setns() 加入一个已存在的 Namespace
int fd = open("/proc/1234/ns/net", O_RDONLY);
setns(fd, CLONE_NEWNET);

生产经验:容器的 Namespace 隔离是"软隔离"——所有容器共享同一个内核。如果一个容器利用了内核漏洞,理论上可以逃逸到宿主机。这就是为什么在安全敏感的多租户 AI 平台上,有些场景需要 Kata Containers(在微虚拟机内运行容器)来提供更强的隔离。

2.2 Cgroup(Control Groups):给进程装上"资源计量表"

Namespace 解决了"看到什么"的问题,但没解决"用多少"的问题。一个容器如果不加限制,它可以吃光宿主机的所有 CPU 和内存。

Cgroup 就是 Linux 内核的资源管理框架——它把进程组织成层级结构,对每个组设定资源使用上限。

Cgroup 层级示例:

/sys/fs/cgroup/
├── cpu/
│   ├── docker/
│   │   ├── container-a/   → CPU 限制: 2 cores
│   │   ├── container-b/   → CPU 限制: 4 cores
│   │   └── container-c/   → CPU 限制: 1 core
│   └── system.slice/      → 系统服务
├── memory/
│   ├── docker/
│   │   ├── container-a/   → 内存限制: 4GB
│   │   ├── container-b/   → 内存限制: 16GB
│   │   └── container-c/   → 内存限制: 2GB
│   └── system.slice/
└── devices/
    └── docker/
        ├── container-a/   → 允许访问: /dev/nvidia0
        └── container-b/   → 允许访问: /dev/nvidia1

Cgroup 可以管理的资源类型

<
控制器 管理的资源 AI 场景关联
cpu CPU 时间片分配 数据预处理、推理前后处理
cpuset 绑定 CPU 核心 NUMA 亲和性优化
memory 内存用量限制 OOM 保护
devices 设备访问控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值