GPU 大模型本地部署复习资料(K8S 集群 GPU 调度与服务部署)
本文最后更新于28 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

本篇聚焦 Kubernetes 集群下的 GPU 算力调度与大模型服务编排,掌握K8s 集群搭建、NVIDIA Device Plugin 原理与部署、三大 AI 框架的容器化编排


一、为什么用 K8s 管理 GPU 集群

1. 无 K8s 管理的核心痛点

痛点具体表现
GPU 资源浪费人工分配粒度粗,显存 / 算力碎片化,昂贵 GPU 空载率高,成本损耗大
任务调度混乱多用户多任务抢卡,人工分配冲突多、效率低,无法按需求弹性分配
服务稳定性差进程崩溃无自动恢复,业务中断;流量波动无法快速扩容,高峰期服务被打挂
扩容运维困难多机管理混乱,环境不一致,部署、迁移、升级成本高、周期长

2. K8s 解决的核心价值

能力说明
自动 GPU 调度集群统一管理 GPU 资源,按需自动分配,资源利用率最大化
自动弹性扩缩基于流量自动增减 Pod 副本,低谷省资源、高峰扛压力
服务自愈Pod 异常崩溃自动重启重建,保证服务持续可用
多机统一管理标准化部署、配置、运维,支持大规模集群高效扩展,环境一致性强

二、K8s 集群部署(⭐)

1. 集群规划示例

主机名IP角色
k8s-master192.168.100.146控制面(CPU)
k8s-node1192.168.100.147工作节点(GPU)

2. 所有节点基础环境配置

2.1 配置 APT 阿里云源

# 备份原源
cp /etc/apt/sources.list /etc/apt/sources.list.backup
# 替换为阿里云镜像
sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
apt update

2.2 设置主机名与主机解析

# Master执行
hostnamectl set-hostname k8s-master && bash
# Worker执行
hostnamectl set-hostname k8s-node1 && bash

# 所有节点添加主机解析
cat <<EOF | sudo tee -a /etc/hosts
192.168.32.14 k8s-master
192.168.32.13 k8s-node1
EOF

2.3 时钟同步

apt install -y chrony
systemctl enable chrony && systemctl start chrony
timedatectl set-timezone Asia/Shanghai

2.4 关闭 Swap(必须,否则 kubelet 无法启动)

# 临时关闭
swapoff -a
# 永久关闭
sed -i '/swap/s/^/#/' /etc/fstab
# 验证
free -h

2.5 关闭防火墙

ufw disable
systemctl stop ufw && systemctl disable ufw

2.6 开启 IPv4 转发与桥接内核参数

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
modprobe br_netfilter

3. 安装 containerd 运行时

# 下载安装
curl -O https://mirrors.aliyun.com/docker-ce/linux/ubuntu/dists/jammy/pool/stable/amd64/containerd.io_1.6.26-1_amd64.deb
dpkg -i containerd.io_1.6.26-1_amd64.deb

# 生成并修改配置
mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 启用SystemdCgroup(与kubelet一致)
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# 替换pause镜像为国内源
sed -i 's#sandbox_image = "registry.k8s.io/pause:.*"#sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.6"#' /etc/containerd/config.toml

# 启动服务
systemctl enable containerd && systemctl restart containerd

4. 配置 crictl 客户端

# 安装
export VERSION="v1.29.0"
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/${VERSION}/crictl-${VERSION}-linux-amd64.tar.gz
tar -zxvf crictl-${VERSION}-linux-amd64.tar.gz -C /usr/local/bin

# 配置
tee /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
EOF

5. 安装 kubeadm/kubelet/kubectl

# 添加GPG密钥与阿里云K8s源
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

# 安装指定版本并锁定
apt update
apt install -y kubelet=1.28.2-00 kubeadm=1.28.2-00 kubectl=1.28.2-00
apt-mark hold kubelet kubeadm kubectl
systemctl enable kubelet

6. Master 节点初始化

# 预拉取镜像
kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version="v1.28.2"

# 初始化集群
kubeadm init \
  --kubernetes-version=v1.28.2 \
  --pod-network-cidr=10.244.0.0/16 \
  --service-cidr=10.96.0.0/12 \
  --image-repository=registry.aliyuncs.com/google_containers

初始化成功后执行配置:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

7. 部署 Flannel 网络插件

kubectl apply -f kube-flannel.yml
# 验证
kubectl get pod -n kube-flannel

8. Worker 节点加入集群

在 Worker 节点执行 Master 初始化输出的kubeadm join命令,格式如下:

kubeadm join 192.168.215.129:6443 \
  --token 97pgmv.vxjakgynflgdh4zw \
  --discovery-token-ca-cert-hash sha256:52163ce2f39c0ccc44558e7339c52bfd006c78944088efb2f94dcc57d424b816

9. 集群状态验证

kubectl get nodes -o wide
kubectl get pods -n kube-system

所有节点状态为Ready、系统 Pod 全部 Running 则集群正常。


三、K8s GPU 算力调度(⭐)

1. NVIDIA Device Plugin 概述

  • 定位:Kubernetes 集群级 GPU 设备管理插件,以 DaemonSet 形式运行在每个 GPU 节点。
  • 核心功能:向 kubelet 注册 GPU 资源、监控 GPU 健康状态、实现 GPU 资源的分配与清理。
  • 工作原理:
    1. 插件通过 gRPC 接口与 kubelet 通信,上报节点 GPU 数量、健康状态
    2. K8s 调度器查询设备资源,将 Pod 调度到有可用 GPU 的节点
    3. Pod 创建时,kubelet 调用插件的 Allocate 接口,将 GPU 设备、驱动库动态注入容器
    4. 容器内应用即可透明使用 GPU,全程标准化调度、无需手动干预

2. 部署前置:NVIDIA Container Toolkit

GPU 节点必须先安装 Container Toolkit,让 containerd 支持 GPU 运行时。

# 1. 添加GPG密钥与软件源
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# 2. 安装指定版本
apt update
export NVIDIA_CONTAINER_TOOLKIT_VERSION=1.17.8-1
apt install -y nvidia-container-toolkit=${NVIDIA_CONTAINER_TOOLKIT_VERSION}

# 3. 配置containerd默认运行时为nvidia
nvidia-ctk runtime configure --runtime=containerd
sed -i 's/default_runtime_name *= *"runc"/default_runtime_name = "nvidia"/g' /etc/containerd/config.toml
systemctl restart containerd

3. 部署 NVIDIA Device Plugin

kubectl apply -f nvidia-device-plugin.yml
  • 部署后会在每个 GPU 节点启动一个插件 Pod,向集群注册nvidia.com/gpu资源类型。

4. 部署验证

# 查看插件日志,无报错则正常
kubectl logs -f nvidia-device-plugin-daemonset-xxx -n kube-system

# 查看节点可分配GPU资源
kubectl describe node k8s-node1 | grep nvidia.com/gpu

5. 易混概念对比

对比项NVIDIA Container ToolkitK8s NVIDIA Device Plugin
作用层级单机容器运行时级别K8s 集群调度级别
核心功能让单个容器能访问 GPU让 K8s 集群能管理、调度 GPU
部署位置宿主机操作系统K8s 集群 DaemonSet
依赖关系依赖 containerd/Docker依赖 Container Toolkit + kubelet
适用场景单机 Docker/containerd 跑 GPU 容器K8s 集群多节点 GPU 编排调度

四、AI 框架 K8s 部署(⭐)

1. Ollama 部署

核心配置要点

  • 资源声明:limits.nvidia.com/gpu: 1 声明申请 1 张 GPU
  • 数据持久化:hostPath 挂载模型目录,避免 Pod 重建丢失模型
  • 服务暴露:NodePort 类型暴露 11434 端口

Deployment 核心片段

spec:
  containers:
  - name: ollama
    image: 192.168.100.149/gpuimages/ollama:latest
    ports:
    - containerPort: 11434
    env:
    - name: OLLAMA_HOST
      value: "0.0.0.0"
    resources:
      limits:
        nvidia.com/gpu: 1
    volumeMounts:
    - name: ollama-data
      mountPath: /root/.ollama
  volumes:
  - name: ollama-data
    hostPath:
      path: /data/ollama

常用操作

# 进入Pod拉取模型
kubectl exec -it ollama-xxx -- bash
ollama pull qwen3.5:4b

# 外部调用API
curl http://节点IP:30114/api/generate -d '{
  "model": "qwen3.5:4b",
  "prompt": "写一个K8s排障流程",
  "stream": false
}'

2. vLLM 部署

核心配置要点

  • 启动命令:通过 command/args 指定模型、并行数、上下文长度等参数
  • 环境变量:开启 ModelScope 加速国内模型下载
  • GPU 资源:声明对应数量的 GPU,支持张量并行
  • 性能优化:建议使用hostNetwork减少网络转发,配置大共享内存

Deployment 核心片段

spec:
  containers:
  - name: vllm
    image: 192.168.100.149/gpuimages/vllm:latest
    command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
    args:
    - "--model"
    - "Qwen/Qwen2-1.5B-Instruct"
    - "--tensor-parallel-size"
    - "1"
    - "--max-model-len"
    - "4096"
    - "--port"
    - "8000"
    - "--host"
    - "0.0.0.0"
    env:
    - name: VLLM_USE_MODELSCOPE
      value: "true"
    resources:
      limits:
        nvidia.com/gpu: 1
    ports:
    - containerPort: 8000

API 验证

curl http://节点IP:30080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2-1.5B-Instruct",
    "messages": [{"role": "user", "content": "介绍一下Kubernetes"}],
    "max_tokens": 512
  }'

3. Open WebUI 部署

核心配置要点

  • 端口映射:容器 8080 端口映射到节点 3000 端口
  • 数据持久化:挂载用户数据、配置、对话记录
  • 环境变量:关闭联网搜索,纯内网离线运行

Deployment 核心片段

spec:
  replicas: 1
  containers:
  - name: open-webui
    image: 192.168.100.149/gpuimages/open-webui:latest
    ports:
    - containerPort: 8080
    env:
    - name: ENABLE_RAG_WEB_SEARCH
      value: "false"
    volumeMounts:
    - name: open-webui-data
      mountPath: /app/backend/data
  volumes:
  - name: open-webui-data
    hostPath:
      path: /data/open-webui

后端对接

  • 对接 Ollama:设置中填写http://ollama-service:11434
  • 对接 vLLM:外部连接中添加 OpenAI 接口http://vllm-service:8000/v1

五、汇总

  • K8s 中 NVIDIA Device Plugin 的工作原理是什么?

插件以 DaemonSet 运行在每个 GPU 节点,通过 gRPC 与 kubelet 通信,上报节点 GPU 数量与健康状态;K8s 调度器根据nvidia.com/gpu资源调度 Pod;Pod 创建时,kubelet 调用插件分配 GPU,将设备节点、驱动库动态注入容器,实现 GPU 的集群级统一调度。

  • 为什么部署 K8s 必须关闭 Swap?

Kubernetes 设计要求节点内存不足时由调度器驱逐 Pod,而不是使用 Swap。Swap 会导致节点性能不稳定、Pod QoS 失效、调度判断失真,因此 kubelet 默认强制要求关闭 Swap 才能启动。

  • containerd 为什么要配置 SystemdCgroup?

kubelet 默认使用 SystemdCgroup 驱动管理容器 cgroup,containerd 必须与其保持一致,否则会出现 cgroup 驱动不匹配错误,导致节点无法正常加入集群、Pod 运行异常。

  • vLLM 部署为什么需要大共享内存(–shm-size)?

答:vLLM 的 PagedAttention、连续批处理机制依赖大量进程间通信和共享内存数据交换;共享内存不足会导致推理性能下降、高并发下报错,因此通常配置数 GB 到十几 GB 的共享内存。

  • K8s 部署 GPU 大模型服务相比裸 Docker 有什么优势?

集群统一调度 GPU,资源利用率更高;服务自愈 + 自动扩缩容,稳定性更强;标准化部署,多机扩展、迁移更方便;支持服务发现、负载均衡、滚动更新,更适合生产级大规模服务。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇