基于K8s的云原生AI基础设施:架构、部署与实践【002】-AI算力的驰骋之地

在 AI 浪潮中,GPU 无疑是最受关注的资源,但真正影响 AI 项目能否落地的,往往并不只是算力本身,而是这些算力能否被有效组织起来。

当 AI 工作负载还停留在单机实验阶段时,几块 GPU 或许已经足够支撑模型开发与测试;但一旦进入团队协作、集群运行和平台化交付阶段,问题就会迅速复杂起来。此时,关键已经不再只是“有没有算力”,而是“这些算力能否被统一管理、按需调度、稳定复用,并支撑后续持续扩展”。

正是在这样的背景下,容器平台,特别是 Kubernetes,逐步成为 AI 算力承载的重要基础。它的意义不只是把应用放进容器里运行,而是通过统一的资源抽象、调度机制和平台能力,把原本分散且复杂的计算资源组织成一个可管理、可复用、可扩展的整体。也正因为如此,Kubernetes 在 AI 场景中的价值,越来越不只是“一个容器编排系统”,而更像是承载 AI 基础设施的平台骨架。

1. 昂贵资源与粗放使用之间的矛盾

在 AI 基础设施建设中,GPU 首先是一类高成本资源。如果每个团队、每个项目都以独占方式使用 GPU 服务器,往往会带来明显的资源浪费:有的任务长时间占用整卡却负载有限,有的任务却只能排队等待可用算力。

Kubernetes 的重要价值之一,就在于它能够通过资源池化和统一调度,把原本分散的 GPU 服务器组织为统一的算力池,为后续的共享、调度和弹性分配提供基础。也就是说,它改变的并不只是资源的使用方式,更是算力的组织方式。

2. 环境复杂与标准化交付之间的矛盾

AI 环境天然复杂,涉及驱动、CUDA、容器运行时、Python 依赖、框架版本以及模型运行环境等多个层面的组合。在缺乏统一平台时,环境不一致往往会成为模型迁移、联调和工程交付中的主要障碍。容器化的意义,就在于尽可能将驱动之外的运行环境收敛到镜像之中,使框架、依赖和应用能够以更标准的方式交付。而 Kubernetes 则进一步把这种能力提升到集群层面,使部署、迁移、复现和版本管理变得更加可控,也为后续的规模化运行打下基础。

3. 单机部署与集群化运行之间的矛盾

在实验阶段,单机部署可能已经足够支撑模型开发与验证;但当场景扩展到多任务并发、批量推理、分布式训练或跨节点协同时,单机模式很快就会触及边界。Kubernetes 天然面向集群环境,能够以统一方式管理跨节点工作负载,并提供扩缩容、服务发现、健康检查和故障恢复等基础能力。对于 AI 工作负载而言,这意味着它不仅能承载单点实验,更能为任务从单机运行走向集群化运行提供稳定的平台基础。

4. 单点实验与平台化建设之间的矛盾

AI 项目真正进入落地阶段后,面对的通常不再是一个临时启动的训练任务,或一次性的推理验证,而是一套需要持续运行和持续演进的工程体系。

从环境准备、资源使用,到任务运行、服务承载,再到后续的监控、调度与扩展,都需要一个统一的平台来支撑。

Kubernetes 的价值,正是在于它让 AI 算力不再停留在“几台 GPU 机器”的层面,而是有机会逐步演进为一套可管理、可调度、可复用、可持续扩展的基础设施能力。

从这个角度出发,这一节真正想讨论的,并不是某一个单点组件,而是一个更基础的问题:为什么 AI 算力需要一个平台化的承载空间,以及 Kubernetes 为什么会成为这个空间中最重要的基础底座之一。

从工程实践的角度来看,理解 Kubernetes 为什么重要只是第一步,更关键的是如何把这个承载平台真正落地。 毕竟,后续无论是 GPU 资源接入、多网络通信、存储挂载、调度增强,还是监控、计量与模型服务部署,几乎都建立在一个稳定可用的 Kubernetes 容器平台之上。

因此,接下来这一部分不再停留在概念层面,而是先回到最基础、也最关键的一步:完成 Kubernetes 容器平台本身的部署与初步验证。 只有当这个平台真正搭建起来,后续围绕 AI 算力展开的各类基础设施能力,才有继续落地和扩展的基础。

下面,就从容器平台的实际部署开始。

主机名与基础主机信息检查(可选)

在生产的规模化环境中,清晰且统一的主机命名有助于后续节点识别、集群维护和故障排查。如果当前主机名不符合规划,可以先进行调整。

# 修改master节点主机名
sudo hostnamectl set-hostname new-hostname gpu-master-135
sudo hostnamectl set-hostname new-hostname gpu-master-136
sudo hostnamectl set-hostname new-hostname gpu-master-137

# 查看当前主机名状态
hostnamectl status

除了主机名本身,还建议同步检查 /etc/hosts 文件是否完整,确保节点之间的名称解析没有明显缺失。

容器运行时准备:安装并配置 containerd

Kubernetes 需要依赖容器运行时来实际启动和管理容器。在当前主流方案中,containerd 是较常见也较稳定的选择之一。因此,在部署 Kubernetes 之前,首先需要完成 containerd 的安装与基础配置。

# Containerd安装部署

# 更新“软件包索引缓存”
sudo apt update

# 安装containerd
sudo apt install -y containerd   

# 安装完成后,先创建 containerd 的标准配置目录,并生成默认配置文件:
sudo mkdir -p /etc/containerd   
sudo containerd config default | sudo tee /etc/containerd/config.toml > /dev/null

# 调整配置文件权限
# containerd 的配置文件属于系统级配置,通常由 root 用户统一管理。因此,建议显式校正配置文件的权限和属主。
sudo chmod 644 /etc/containerd/config.toml
sudo chown root:root /etc/containerd/config.toml
# 启动并设置开机自启
systemctl restart containerd && systemctl enable containerd

# 可选检查项,如果需要确认可安装版本或当前运行版本,可以执行以下命令:
# 查看当前可安装版本
sudo apt-cache madison containerd

# 检查 containerd 和 runc 版本
containerd -v
runc -v

系统内核模块准备

# 立即加载内核模块
sudo modprobe overlay
sudo modprobe br_netfilter
sudo modprobe vxlan

# 对模块进行固化使其开机加载
sudo tee /etc/modules-load.d/k8s.conf >/dev/null << 'EOF'
overlay
br_netfilter
vxlan
EOF

 # 验证模块是否已加载
 lsmod | egrep 'overlay|vxlan|br_netfilter'
 # 也可以逐项确认:
for m in overlay br_netfilter vxlan; do
  lsmod | grep -q "$m" && echo "$m loaded" || echo "$m not loaded"
done
# 如需查看模块详细信息,可使用:
modinfo vxlan

网络环境准备

为了让 Kubernetes 的 Pod 网络和 Service 转发机制正常工作,需要提前设置几个关键的内核网络参数。其中最常见的要求包括:允许桥接流量进入 iptables 处理链,并开启 IPv4 转发。

# 在/etc/sysctl.d/k8s.conf中写入三条 Kubernetes 网络所需的内核转发规则(让容器桥接流量能被 iptables 管理、允许主机做 IP 转发),为 Pod 间通信和 Service 转发功能铺路。
sudo tee /etc/sysctl.d/k8s.conf >/dev/null << 'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# 应用内核转发规则
sudo sysctl --system

# 验证配置是否生效
sysctl net.bridge.bridge-nf-call-iptables \\
       net.bridge.bridge-nf-call-ip6tables \\
       net.ipv4.ip_forward

系统运行环境准备

除了容器运行时和内核参数,Kubernetes 还对系统运行环境有一些常见要求。这里主要包括:关闭 Swap、调整 cgroup 驱动,以及修改 pause 镜像地址。

# 1. 关闭 Swap
# Kubernetes 通常要求关闭 Swap,否则可能影响调度与资源管理行为。这里先关闭当前生效的 Swap,并同步修改 /etc/fstab,确保重启后依旧生效。
sudo swapoff -a 

# 备份fstab文件
sudo cp /etc/fstab /etc/fstab.old

# 把所有包含 swap 的行注释掉,(永久生效)
sudo sed -i -E 's/^(.*swap.*)$/#\\1/' /etc/fstab

# 验证方式:
free -m

# 2. 配置 systemd cgroup 驱动
# 为了让 containerd 与 Kubernetes 在 cgroup 驱动方式上保持一致,通常会将 SystemdCgroup 设置为 true。
sudo sed -i 's/^\\(\\s*SystemdCgroup = \\)false/\\1true/' /etc/containerd/config.toml

# 验证方式:
grep 'SystemdCgroup' /etc/containerd/config.toml

# 调整 pause 镜像地址

# 3. pause 镜像是 Pod 基础命名空间容器所依赖的系统镜像。默认情况下,containerd 会从 registry.k8s.io 拉取该镜像;如果网络环境受限,建议替换为国内可访问性更高的镜像源。
sudo sed -i 's#registry.k8s.io/pause:[^"]*#registry.aliyuncs.com/google_containers/pause:3.10#g' /etc/containerd/config.toml
# 修改后重启 containerd:
sudo systemctl restart containerd

# 验证方式:
grep 'pause' /etc/containerd/config.toml
systemctl status containerd.service

完成基础环境准备之后,容器平台已经具备了安装 Kubernetes 的前提条件。 接下来,真正的部署工作才正式开始:先安装 kubeadm、kubelet 和 kubectl 这三个核心组件,再基于 kubeadm 初始化 Master 节点,完成 Kubernetes 控制平面的创建。

这一部分的重点不再是系统参数调整,而是把前面准备好的运行环境真正转化为一个可用的 Kubernetes 集群。后续无论是 Worker 节点加入、网络插件部署,还是 GPU、存储、调度等能力的接入,都将建立在这一步完成的基础之上。

安装 Kubernetes 的核心组件:kubeadmkubeletkubectl。 其中,kubeadm 用于初始化和管理集群,kubelet 负责节点上的 Pod 生命周期管理,kubectl 则是后续操作集群的主要命令行工具。

为了确保版本一致性和后续可控升级,这里采用官方 apt 软件源安装指定版本,并在安装后将其锁定,避免系统自动升级导致版本漂移。

安装 Kubernetes 三件套

安装 Kubernetes 的核心组件:kubeadmkubeletkubectl。其中,kubeadm 用于初始化和管理集群,kubelet 负责节点上的 Pod 生命周期管理,kubectl 则是后续操作集群的主要命令行工具。为了确保版本一致性和后续可控升级,这里采用官方 apt 软件源安装指定版本,并在安装后将其锁定,避免系统自动升级导致版本漂移。

# 安装前置依赖
sudo apt-get update && apt-get install -y apt-transport-https ca-certificates curl gpg 

# 下载K8s v1.33 apt仓库的GPG公钥,把它转换成apt能用的.gpg keyring文件存到 /etc/apt/keyrings/,让后续 apt-get install kubelet/kubeadm/kubectl 时能安全验证来源。
sudo curl -fsSL <https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key> | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# 在系统里注册 Kubernetes v1.33 的官方 apt 软件源,
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] <https://pkgs.k8s.io/core:/stable:/v1.33/deb/> /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# 更新“软件包索引缓存”
sudo apt update

# 安装指定版本
sudo apt-get install -y kubelet=1.33.5-1.1 kubeadm=1.33.5-1.1 kubectl=1.33.5-1.1

# 设置不随系统更新而更新
sudo apt-mark hold kubelet kubeadm kubectl

# 基础检查
apt-cache madison kubectl
kubectl version --client

集群初始化方式说明

在实际部署中,Kubernetes 控制平面的搭建方式通常分为两类:一种是单 Master 部署,适合测试环境、小规模验证或对高可用要求不高的场景;另一种是多 Master 高可用部署,适合生产环境或对控制平面连续性有更高要求的场景。

下面分别说明这两种部署方式。

单Master节点部署

单 Master 模式的优点是结构简单、部署直接,适合快速完成集群初始化。在这一模式下,首先通过 kubeadm init 初始化控制平面,再为当前用户配置 kubectl 管理权限,最后生成 Worker 节点加入命令。

# 初始化控制平面
sudo kubeadm init --apiserver-advertise-address=10.118.17.28 --image-repository [registry.aliyuncs.com/google_containers](<http://registry.aliyuncs.com/google_containers>) --kubernetes-version v1.33.5 --service-cidr=10.88.0.0/12 --pod-network-cidr=10.86.0.0/16 --cri-socket unix:///run/containerd/containerd.sock

# 这里几个参数尤其值得注意:
* --apiserver-advertise-address:指定当前 Master 节点对外通告的 API Server 地址
* --service-cidr:Service 网络地址段
* --pod-network-cidr:Pod 网络地址段,后续需要和所选 CNI 插件配置保持一致
* --cri-socket:指定容器运行时套接字,确保 kubeadm 使用的是 containerd

# 配置 kubectl 使用权限
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# admin.conf 是 kubeadm 初始化后生成的集群管理员配置文件。只有将它复制到当前用户的 kubeconfig 路径下,后续才能直接使用 kubectl 管理集群。

# 启用命令补全
source <(kubectl completion bash) 
echo "source <(kubectl completion bash)" >> ~/.bashrc

source <(kubeadm completion bash)
echo "source <(kubeadm completion bash)" >> ~/.bashrc

# worke节点加入
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>

# 这个命令会在 kubeadm init 成功后自动输出。后续所有 Worker 节点都需要依赖该命令加入集群。

Master高可用部署

如果集群用于生产环境,通常需要进一步构建控制平面的高可用能力。在 kubeadm 方案下,常见做法是在多台 Master 前面增加一层 API Server 访问入口,并配合 VIP 提供统一接入地址。这里采用的组合是:

  • HAProxy:负责 API Server 的四层转发与负载均衡
  • Keepalived:负责 VIP 漂移与高可用接入

这样做的目的,是为多个 Master 节点提供一个稳定的控制平面入口地址,避免客户端直接绑定某一台具体 Master。

# 1. 部署 HAProxy ,
# 在这里主要承担 Kubernetes API Server 的统一访问入口。
sudo apt install -y haproxy

# 修改haproxy的配置文件
# 需要把前端监听端口映射到多个 Master 节点的 6443 端口,并通过 TCP 层做健康检查和轮询转发。
sudo vi /etc/haproxy/haproxy.cfg  
  
global
   log /dev/log local0
   log /dev/log local1 notice
   maxconn 2000
defaults
   log global
   mode tcp
   option tcplog
   timeout client 10s
   timeout server 10s
   timeout connect 10s
frontend k8s-api
   bind *:8443
   default_backend k8s-api-backend
backend k8s-api-backend
   balance roundrobin
   server gpu-master-135 10.x.x.135:6443 check
   server gpu-master-136 10.x.x.136:6443 check
   server gpu-master-137 10.x.x.137:6443 check

systemctl start haproxy 
systemctl enable haproxy 
sudo systemctl restart haproxy

# 检查
# 配置完成后,建议至少确认以下两点:
* HAProxy 服务已正常启动
* 负载均衡监听端口已经成功建立
sudo ss -tnlp | grep 8443 || echo "no 8443 listener"

# 2. 部署 Keepalived
# Keepalived 的作用,是在多台节点之间维护一个可漂移的 VIP。这样,无论后端具体由哪一台机器提供入口能力,外部客户端看到的始终是同一个控制平面地址。
sudo apt install -y keepalived

# 修改keepalived的配置文件   
sudo vi /etc/keepalived/keepalived.conf   

vrrp_instance VI_1 {
    state MASTER               # 这个节点是 MASTER
    interface bond0            # 使用的物理网卡名,按实际改
    virtual_router_id 51       # VRID,同一组 Keepalived 要一致
    priority 100               # 优先级,MASTER 比 BACKUP 大
    advert_int 1               # 心跳间隔(秒)

    authentication {
        auth_type PASS
        auth_pass xxxx       # 自己定义的密码,同一组必须一致
    }

    virtual_ipaddress {
        10.x.x.200/24        # 对外漂移的 VIP
    }
}

systemctl start keepalived 
systemctl enable keepalived
sudo systemctl restart keepalived

# 检查
sudo systemctl status haproxy
sudo systemctl status keepalived

初始化第一台 Master

在高可用场景下,第一台 Master 节点通常采用 kubeadm 配置文件方式初始化,而不是直接在命令行中拼接全部参数。这样做的好处是参数更集中、可读性更高,也更便于后续复用和审计。

**# 第一台Master节点部署**

kubeadm config print init-defaults > init-defaults.yaml
kubeadm init --config init-defaults.yaml

# 初始化完成后,同样需要配置当前用户的 kubectl 使用权限(此处省略),并部署网络 CNI。
kubectl apply -f kube-flannel.yml

其他 Master 与 Worker 节点加入

# 获取控制平面加入信息
# 多 Master 加入时,除了普通节点加入所需的 token 和 CA hash,还需要额外使用 certificate key 来分发控制平面证书。
# 找到certificate key
sudo kubeadm init phase upload-certs --upload-certs

# 获取 join 命令
kubeadm token create --print-join-command

# 第二台/第三台 Master节点加入
在拿到 certificate key、token 和 discovery-token-ca-cert-hash 之后,就可以让其余 Master 节点加入控制平面。
sudo kubeadm join 10.x.x.200:8443 \\
  --token xxx \\
  --discovery-token-ca-cert-hash sha256:216e75xxx8435e0c1b143a10ce93fd0d22019c6b0cf34522e20d5e6 \\
  --control-plane \\
  --certificate-key 6e401233xxx8d61f88b81f7f306d3677c76 \\
  --cri-socket unix:///var/run/containerd/containerd.sock
      
# 所有worker节点加入
Worker 节点则只需要执行普通的 join 命令即可。
sudo kubeadm join 10.x.x.200:8443 --token abcdef.012345xxxef \\
        --discovery-token-ca-cert-hash sha256:57a047xxx2d61863cef974d37204

到这里,Kubernetes 控制平面已经完成初始化,容器平台也具备了最基本的运行基础。但对于一个面向 AI 场景的集群来说,仅仅完成 Master 节点部署还远远不够。真正进入实际使用阶段后,通常还需要接入大量 Worker 节点,并在这些节点上统一完成容器运行时、内核参数、Kubernetes 组件、镜像仓库访问等基础配置。

如果这些步骤仍然依赖手工逐台执行,不仅效率低,而且很容易出现配置不一致、版本漂移和遗漏项,最终影响整个集群的稳定性与可维护性。也正因为如此,在节点规模开始扩大之后,集群建设就必须从“手工部署”进一步走向“自动化交付”。基于这个考虑,下一小节将引入 Ansible,对 Worker Node 的基础配置和节点接入过程进行批量化处理。

Leave a Reply