文章目录
- Kubernetes 集群初始化问题总结文档
-
- 概述
- 遇到的问题及解决方案
-
- 1. Kubelet cgroup 驱动配置错误
- 2. CoreDNS Pod 处于 Pending 状态
- 3. 节点污点阻止 CoreDNS 调度
- 1. Kubelet cgroup 驱动配置错误
- 最终验证结果
- 经验总结
- 问题已解决!🎉
Kubernetes 集群初始化问题总结文档
概述
本文档总结了在 Kubernetes 集群初始化过程中遇到的主要问题及其解决方案。通过系统性的诊断和修复,最终成功建立了稳定运行的 Kubernetes 控制平面。
遇到的问题及解决方案
1. Kubelet cgroup 驱动配置错误
问题描述:
在集群初始化完成后,发现 kubelet 服务存在 cgroup 驱动配置错误。日志显示 kubelet 配置中的 cgroupDriver 被设置为 “systemd”,但实际需要的是 “cgroupfs”。
诊断过程:
- 检查
/var/lib/kubelet/config.yaml配置文件 - 确认
cgroupDriver字段值为 “systemd” - 查看 kubelet 服务日志确认配置问题
解决方案:
- 使用 sed 命令将配置文件中的
cgroupDriver: systemd修改为cgroupDriver: cgroupfs - 重启 kubelet 服务以应用更改
- 验证修改结果,通过日志确认 CgroupDriver 已正确设置为 “cgroupfs”
2. CoreDNS Pod 处于 Pending 状态
问题描述:
集群初始化后,CoreDNS Pod 一直处于 Pending 状态,无法正常启动。
诊断过程:
- 检查 Pod 状态发现 CoreDNS 处于 Pending
- 分析原因发现缺少网络插件支持
- 检查发现存在 calico.yaml 配置文件
解决方案:
- 应用 Calico 网络插件配置:
kubectl apply -f ~/calico.yaml - 等待 Calico 组件启动完成
- 观察 CoreDNS Pod 状态变化
3. 节点污点阻止 CoreDNS 调度
问题描述:
即使部署了网络插件,CoreDNS Pod 仍然处于 Pending 状态。
诊断过程:
- 检查节点污点配置发现存在
node-role.kubernetes.io/master:NoSchedule - 检查 CoreDNS 部署的容忍度设置
- 发现 CoreDNS 有容忍
control-plane但节点标记为master
解决方案:
- 移除节点上的 master 污点:
kubectl taint nodes --all node-role.kubernetes.io/master- - 等待 CoreDNS Pod 自动调度并启动
最终验证结果
所有问题解决后,集群状态恢复正常:
- 节点状态:Ready
- 所有系统组件正常运行:
- etcd
- kube-apiserver
- kube-controller-manager
- kube-scheduler
- kube-proxy
- CoreDNS
- Calico 网络插件
经验总结
- 配置一致性很重要:确保 kubelet 配置与容器运行时的 cgroup 驱动保持一致
- 网络插件必不可少:CoreDNS 等组件依赖网络插件才能正常工作
- 污点和容忍度需要匹配:节点上的污点必须与 Pod 的容忍度设置相匹配才能正常调度
- 系统性诊断方法:从日志分析入手,逐步排查问题根源
通过以上步骤,成功解决了 Kubernetes 集群初始化过程中遇到的关键问题,确保了集群的稳定运行。
/home/user/k8s_init_complete_v2.sh
1#!/bin/bash 2 3YELLOW="\033[1;33m" 4GREEN="\033[1;32m" 5RED="\033[1;31m" 6RESET="\033[0m" 7 8echo -e "${YELLOW}=== Kubernetes 初始化完善执行流程 ===${RESET}" 9 10# 阶段一:环境清理与依赖检查(基础保障) 11echo -e "${YELLOW}=== 阶段一:环境清理与依赖检查 ===${RESET}" 12 13# 步骤 1:清理历史残留 14echo -e "${YELLOW}=== 步骤 1/20:清理历史残留 ===${RESET}" 15# 先启动 containerd 服务,避免 kubeadm reset 出现连接错误 16echo "启动 containerd 服务..." 17sudo systemctl start containerd 2>/dev/null || true 18# 等待 containerd 启动 19sleep 5 20# 重置 kubeadm 21sudo kubeadm reset -f 22# 删除残留文件 23sudo rm -rf /etc/kubernetes/* /var/lib/kubelet/* /var/lib/etcd/* /etc/cni/net.d/* /home/user/kubeadm-config.yaml ~/.kube/config 24echo -e "${GREEN}=== 步骤 1 执行完成 ===${RESET}" 25 26# 步骤 2:检查系统依赖(必过校验) 27echo -e "${YELLOW}=== 步骤 2/20:检查系统依赖 ===${RESET}" 28# 校验内核版本(需 ≥4.19) 29kernel_version=$(uname -r | cut -d '.' -f1-2) 30if [[ $(echo "$kernel_version >= 4.19" | bc) -ne 1 ]]; then 31 echo -e "${RED}❌ 内核版本过低(当前 $kernel_version),需升级至 4.19+${RESET}" 32 exit 1 33fi 34 35# 校验关键工具是否安装 36required_tools=("kubeadm" "kubelet" "kubectl" "containerd" "crictl" "ss" "jq") 37for tool in "${required_tools[@]}"; do 38 if ! command -v $tool &> /dev/null; then 39 echo -e "${RED}❌ 缺失依赖工具:$tool,请先安装${RESET}" 40 exit 1 41 fi 42done 43 44# 校验端口占用(6443/2379/2380/10250 需空闲) 45occupied_ports=() 46for port in 6443 2379 2380 10250; do 47 if sudo ss -tuln | grep -q ":$port"; then 48 occupied_ports+=($port) 49 fi 50done 51if [[ ${#occupied_ports[@]} -gt 0 ]]; then 52 echo -e "${RED}❌ 端口被占用:${occupied_ports[*]},请释放后重试${RESET}" 53 exit 1 54fi 55 56echo -e "${GREEN}✅ 步骤 2 校验通过:系统依赖满足要求${RESET}" 57 58# 阶段二:Containerd 配置与校验(核心组件) 59echo -e "${YELLOW}=== 阶段二:Containerd 配置与校验 ===${RESET}" 60 61# 步骤 3:配置 Containerd(cgroupfs 驱动) 62echo -e "${YELLOW}=== 步骤 3/20:配置 Containerd ===${RESET}" 63sudo tee /etc/containerd/config.toml > /dev/null << EOF 64version = 2 65root = "/var/lib/containerd" 66state = "/run/containerd" 67plugin_dirs = [] 68 69[grpc] 70 address = "/run/containerd/containerd.sock" 71 uid = 0 72 gid = 0 73 74[ttrpc] 75 address = "" 76 uid = 0 77 gid = 0 78 79[debug] 80 address = "" 81 uid = 0 82 gid = 0 83 level = "" 84 85[metrics] 86 address = "" 87 grpc_histogram = false 88 89[cgroup] 90 path = "" 91 92[timeouts] 93 "io.containerd.timeout.shim.cleanup" = "5s" 94 "io.containerd.timeout.shim.load" = "5s" 95 "io.containerd.timeout.shim.shutdown" = "3s" 96 "io.containerd.timeout.task.state" = "2s" 97 98[plugins] 99 [plugins."io.containerd.grpc.v1.cri"] 100 disable_tcp_service = true 101 stream_server_address = "127.0.0.1" 102 stream_server_port = "0" 103 stream_idle_timeout = "4h0m0s" 104 enable_tls_streaming = false 105 sandbox_image = "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/pause:3.10.1" 106 stats_collect_period = 10 107 systemd_cgroup = false 108 enable_selinux = false 109 selinux_category_range = 1024 110 max_container_log_line_size = 16384 111 disable_cgroup = false 112 disable_apparmor = false 113 restrict_oom_score_adj = false 114 max_concurrent_downloads = 3 115 max_concurrent_uploads = 5 116 disable_proc_mount = false 117 unset_seccomp_profile = "" 118 tolerate_missing_hugetlb_controller = true 119 disable_hugetlb_controller = true 120 ignore_image_defined_volumes = false 121 netns_mounts_under_state_dir = false 122 enable_unprivileged_ports = false 123 enable_unprivileged_icmp = false 124 125 [plugins."io.containerd.grpc.v1.cri".containerd] 126 default_runtime_name = "runc" 127 disable_snapshot_annotations = true 128 discard_unpacked_layers = false 129 ignore_rdt_not_enabled_errors = false 130 131 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] 132 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 133 runtime_type = "io.containerd.runc.v2" 134 runtime_engine = "" 135 runtime_root = "" 136 privileged_without_host_devices = false 137 base_runtime_spec = "" 138 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 139 SystemdCgroup = false 140 141 [plugins."io.containerd.grpc.v1.cri".cni] 142 bin_dir = "/opt/cni/bin" 143 conf_dir = "/etc/cni/net.d" 144 max_conf_num = 1 145 conf_template = "" 146 [plugins."io.containerd.grpc.v1.cri".cni.ipam] 147 [plugins."io.containerd.grpc.v1.cri".cni.interface] 148 149 [plugins."io.containerd.grpc.v1.cri".registry] 150 config_path = "" 151 152 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 153 [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] 154 endpoint = ["https://registry-1.docker.io"] 155 [plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.cn-hangzhou.aliyuncs.com"] 156 endpoint = ["https://registry.cn-hangzhou.aliyuncs.com"] 157 158[plugins."io.containerd.internal.v1.opt"] 159 path = "/opt/containerd" 160 161[plugins."io.containerd.monitor.v1.cgroups"] 162 no_prometheus = false 163 164[plugins."io.containerd.runtime.v2.task"] 165 platforms = ["linux/amd64"] 166 167[plugins."io.containerd.service.v1.containers-service"] 168 rdt_config_file = "" 169 170[plugins."io.containerd.snapshotter.v1.btrfs"] 171 root_path = "/var/lib/containerd/snapshots/btrfs" 172 173[plugins."io.containerd.snapshotter.v1.native"] 174 root_path = "/var/lib/containerd/snapshots/native" 175 176[plugins."io.containerd.snapshotter.v1.overlayfs"] 177 root_path = "/var/lib/containerd/snapshots/overlayfs" 178 179[plugins."io.containerd.snapshotter.v1.zfs"] 180 root_path = "/var/lib/containerd/snapshots/zfs" 181EOF 182echo -e "${GREEN}=== 步骤 3 执行完成 ===${RESET}" 183 184# 步骤 4:启动 Containerd 并校验 185echo -e "${YELLOW}=== 步骤 4/20:启动并校验 Containerd ===${RESET}" 186# 重启服务 187sudo systemctl daemon-reload 188sudo systemctl start containerd 189sudo systemctl enable containerd 190 191# 等待启动(10秒) 192sleep 10 193 194# 校验状态(必须为 active (running)) 195if ! sudo systemctl is-active --quiet containerd; then 196 echo -e "${RED}❌ Containerd 启动失败,查看日志:sudo journalctl -u containerd -n 20${RESET}" 197 exit 1 198fi 199 200# 校验 cgroup 驱动配置(必须为 false,即 cgroupfs) 201if ! grep -qE "systemd_cgroup = false|SystemdCgroup = false" /etc/containerd/config.toml; then 202 echo -e "${RED}❌ Containerd cgroup 驱动配置错误,未启用 cgroupfs${RESET}" 203 exit 1 204fi 205 206# 校验 CRI 接口连通性 207if ! sudo crictl info &> /dev/null; then 208 echo -e "${RED}❌ CRI 接口连通失败,Containerd 配置异常${RESET}" 209 exit 1 210fi 211 212echo -e "${GREEN}✅ 步骤 4 校验通过:Containerd 正常运行(cgroupfs 驱动)${RESET}" 213 214# 步骤 5:预拉取 Pause 镜像(避免后续组件启动时重复拉取) 215echo -e "${YELLOW}=== 步骤 5/20:预拉取 Pause 镜像 ===${RESET}" 216# 检查镜像是否已存在,如果不存在则拉取 217if ! sudo ctr -n k8s.io images ls | grep -q "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/pause:3.10.1"; then 218 if ! sudo ctr -n k8s.io images pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/pause:3.10.1; then 219 echo -e "${RED}❌ Pause 镜像拉取失败,检查网络或镜像仓库${RESET}" 220 exit 1 221 fi 222else 223 echo -e "${GREEN}✅ Pause 镜像已存在,跳过拉取${RESET}" 224fi 225echo -e "${GREEN}=== 步骤 5 执行完成 ===${RESET}" 226# 注释掉原来的拉取命令,避免重复拉取 227# pause_image="registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.9" 228# if ! sudo crictl pull $pause_image; then 229# echo -e "${RED}❌ Pause 镜像拉取失败,检查网络或镜像仓库${RESET}" 230# exit 1 231# fi 232 233echo -e "${GREEN}✅ 步骤 5 校验通过:Pause 镜像拉取成功${RESET}" 234 235# 阶段三:Kubelet 配置与校验(节点代理) 236echo -e "${YELLOW}=== 阶段三:Kubelet 配置与校验 ===${RESET}" 237 238# 步骤 6:配置 Kubelet 服务 239echo -e "${YELLOW}=== 步骤 6/20:配置 Kubelet 服务 ===${RESET}" 240sudo mkdir -p /etc/systemd/system/kubelet.service.d/ 241sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf > /dev/null << EOF 242[Service] 243Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf" 244Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml" 245# 移除不支持的 --container-runtime 标志,将其配置在 config.yaml 文件中 246Environment="KUBELET_EXTRA_ARGS=--cgroup-driver=cgroupfs" 247ExecStart= 248ExecStart=/usr/bin/kubelet \$KUBELET_KUBECONFIG_ARGS \$KUBELET_CONFIG_ARGS \$KUBELET_EXTRA_ARGS 249EOF 250echo -e "${GREEN}=== 步骤 6 执行完成 ===${RESET}" 251 252# 步骤 7:创建 Kubelet 配置文件 253echo -e "${YELLOW}=== 步骤 7/20:创建 Kubelet 配置文件 ===${RESET}" 254sudo mkdir -p /var/lib/kubelet 255sudo tee /var/lib/kubelet/config.yaml > /dev/null << EOF 256apiVersion: kubelet.config.k8s.io/v1beta1 257kind: KubeletConfiguration 258cgroupDriver: cgroupfs 259runtimeRequestTimeout: "15m" 260maxPods: 110 261containerRuntimeEndpoint: "unix:///run/containerd/containerd.sock" 262EOF 263echo -e "${GREEN}=== 步骤 7 执行完成 ===${RESET}" 264 265# 阶段四:镜像预拉与配置文件创建(初始化前置) 266echo -e "${YELLOW}=== 阶段四:镜像预拉与配置文件创建 ===${RESET}" 267 268# 步骤 8:预拉取 K8s 核心镜像(避免初始化时拉取超时) 269echo -e "${YELLOW}=== 步骤 8/20:预拉取 K8s 核心镜像 ===${RESET}" 270images=( 271 "registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.33.5" 272 "registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.33.5" 273 "registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.33.5" 274 "registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.33.5" 275 "registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.12.0" 276 "registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.12-0" 277 "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/pause:3.10.1" 278) 279 280for image in "${images[@]}"; do 281 # 检查镜像是否已存在,如果不存在则拉取 282 if ! sudo ctr -n k8s.io images ls | grep -q "$image"; then 283 if ! sudo ctr -n k8s.io images pull "$image"; then 284 echo -e "${RED}❌ 镜像拉取失败: $image${RESET}" 285 exit 1 286 fi 287 else 288 echo -e "${GREEN}✅ 镜像已存在,跳过拉取: $image${RESET}" 289 fi 290done 291echo -e "${GREEN}=== 步骤 8 执行完成 ===${RESET}" 292# 注释掉原来的拉取命令,避免重复拉取 293# if ! sudo kubeadm config images pull --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --kubernetes-version=v1.33.5; then 294# echo -e "${RED}❌ K8s 镜像拉取失败,检查网络或镜像仓库地址${RESET}" 295# exit 1 296# fi 297 298# 校验镜像是否拉取成功(使用实际拉取的镜像版本,适配crictl输出格式) 299echo -e "${YELLOW}=== 校验镜像是否拉取成功 ===${RESET}" 300required_images=( 301 "kube-apiserver:v1.33.5" 302 "kube-controller-manager:v1.33.5" 303 "kube-scheduler:v1.33.5" 304 "etcd:3.5.12-0" 305 "coredns:v1.12.0" 306) 307 308# 获取镜像列表 309image_list=$(sudo crictl images --quiet) 310 311# 检查每个必需的镜像 312for img in "${required_images[@]}"; do 313 # 提取镜像名称和标签 314 image_name=$(echo "$img" | cut -d':' -f1) 315 image_tag=$(echo "$img" | cut -d':' -f2) 316 317 # 构造搜索模式 318 search_pattern="${image_name}\s\+${image_tag}" 319 320 # 检查镜像是否存在 321 if ! sudo crictl images | grep -q "$search_pattern"; then 322 echo -e "${RED}❌ 缺失核心镜像:$img,请重新拉取${RESET}" 323 exit 1 324 fi 325done 326 327echo -e "${GREEN}✅ 步骤 8 校验通过:K8s 核心镜像拉取完成${RESET}" 328 329# 步骤 9:创建 Kubeadm 配置文件 330echo -e "${YELLOW}=== 步骤 9/20:创建 Kubeadm 配置文件 ===${RESET}" 331sudo tee /home/user/kubeadm-config.yaml > /dev/null << EOF 332apiVersion: kubeadm.k8s.io/v1beta3 333kind: InitConfiguration 334localAPIEndpoint: 335 advertiseAddress: 10.16.233.177 336 bindPort: 6443 337nodeRegistration: 338 criSocket: unix:///run/containerd/containerd.sock 339 taints: 340 - effect: NoSchedule 341 key: node-role.kubernetes.io/master 342--- 343apiVersion: kubeadm.k8s.io/v1beta3 344kind: ClusterConfiguration 345kubernetesVersion: v1.33.5 346imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers 347networking: 348 podSubnet: 192.168.0.0/16 349controlPlaneEndpoint: "10.16.233.177:6443" 350controllerManager: 351 extraArgs: 352 configure-cloud-routes: "false" 353scheduler: 354 extraArgs: 355 bind-address: 0.0.0.0 # 修复:将 address 改为 bind-address(当前版本支持的参数) 356EOF 357 358# 校验配置文件语法(必须无报错) 359if ! kubeadm config validate --config=/home/user/kubeadm-config.yaml; then 360 echo -e "${RED}❌ Kubeadm 配置文件语法错误,请检查格式${RESET}" 361 exit 1 362fi 363 364echo -e "${GREEN}✅ 步骤 9 校验通过:Kubeadm 配置文件有效${RESET}" 365 366 367# 阶段五:K8s 初始化与核心校验(关键阶段) 368echo -e "${YELLOW}=== 阶段五:K8s 初始化与核心校验 ===${RESET}" 369 370# 步骤 10:启动 Kubelet 服务 371echo -e "${YELLOW}=== 步骤 10/20:启动 Kubelet 服务 ===${RESET}" 372# 重启服务 373sudo systemctl daemon-reload 374sudo systemctl start kubelet 375sudo systemctl enable kubelet 376echo -e "${GREEN}=== 步骤 10 执行完成 ===${RESET}" 377 378# 步骤 11:执行 Kubeadm 初始化 379echo -e "${YELLOW}=== 步骤 11/20:执行 Kubeadm 初始化 ===${RESET}" 380# 开启 debug 日志,便于排查 381sudo kubeadm init --config=/home/user/kubeadm-config.yaml --ignore-preflight-errors=all --v=5 382 383# 校验初始化是否成功(必须返回 0) 384if [ $? -ne 0 ]; then 385 echo -e "${RED}❌ Kubeadm 初始化失败,查看日志:sudo journalctl -u kubelet -n 50${RESET}" 386 exit 1 387fi 388 389echo -e "${GREEN}✅ 步骤 11 执行完成:Kubeadm 初始化无语法错误${RESET}" 390 391# 步骤 12:校验 Kubelet 状态 392echo -e "${YELLOW}=== 步骤 12/20:校验 Kubelet 状态 ===${RESET}" 393# 等待启动(5秒) 394sleep 5 395 396# 校验状态(必须为 active (running)) 397if ! sudo systemctl is-active --quiet kubelet; then 398 echo -e "${RED}❌ Kubelet 启动失败,查看日志:sudo journalctl -u kubelet -n 20${RESET}" 399 exit 1 400fi 401 402# 校验 cgroup 驱动配置(日志中必须含 CgroupDriver: cgroupfs) 403if ! sudo journalctl -u kubelet -n 10 --no-pager | grep -q "CgroupDriver: cgroupfs"; then 404 echo -e "${RED}❌ Kubelet cgroup 驱动配置错误,未启用 cgroupfs${RESET}" 405 exit 1 406fi 407 408echo -e "${GREEN}✅ 步骤 12 校验通过:Kubelet 正常运行(cgroupfs 驱动)${RESET}" 409 410# 步骤 13:配置 Kubectl 客户端 411echo -e "${YELLOW}=== 步骤 13/20:配置 Kubectl 客户端 ===${RESET}" 412mkdir -p $HOME/.kube 413sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 414sudo chown $(id -u):$(id -g) $HOME/.kube/config 415 416# 校验 Kubectl 连通性(必须返回集群版本) 417if ! kubectl version --short; then 418 echo -e "${RED}❌ Kubectl 客户端配置失败,无法连接集群${RESET}" 419 exit 1 420fi 421 422echo -e "${GREEN}✅ 步骤 13 校验通过:Kubectl 客户端配置成功${RESET}" 423 424echo -e "${GREEN}=== Kubernetes 初始化完善执行流程完成 ===${RESET}" 425
明白了,K8S使用的是containerd而不是Docker。让我检查containerd的默认运行时配置:
user 终端
sudo grep -A 20 “default_runtime_name” /etc/containerd/config.toml
问题就是这里!containerd的默认运行时还是 runc ,需要改为 nvidia 。让我修改配置:
user 终端
sudo sed -i ‘s/default_runtime_name = “runc”/default_runtime_name = “nvidia”/’ /etc/containerd/config.toml
现在重启containerd:
user 终端
sudo systemctl restart containerd
现在删除Device Plugin Pod让它重新创建:
user 终端
kubectl delete pod -n kube-system -l name=nvidia-device-plugin-ds
等待几秒钟后检查新Pod状态:
user 终端
sleep 10 && kubectl get pods -n kube-system | grep nvidia-device-plugin
还是有问题。让我检查新的日志:
user 终端
kubectl logs -n kube-system nvidia-device-plugin-daemonset-6h2fg
检查Pod描述:
user 终端
kubectl describe pod nvidia-device-plugin-daemonset-6h2fg -n kube-system | grep -A 10 “Last State”
现在错误变成了CDI设备解析问题。让我检查CDI配置:
user 终端
sudo nvidia-ctk cdi list
CDI设备列表为空!让我生成CDI配置:
user 终端
sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
看来CDI模式有问题。让我回到更简单的方案,修改Device Plugin使用传统模式。先删除现有的DaemonSet:
user 终端
kubectl delete daemonset nvidia-device-plugin-daemonset -n kube-system
现在用环境变量禁用CDI模式,使用传统模式:
user 终端
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/main/deployments/static/nvidia-device-plugin.yml -o yaml | sed ‘s/- name: FAIL_ON_INIT_ERROR\n value: “false”/- name: FAIL_ON_INIT_ERROR\n value: “false”\n - name: DEVICE_DISCOVERY_STRATEGY\n value: “nvml”/’ | kubectl apply -f -
让我用更简单的方法,直接下载YAML文件并修改:
user 终端
curl -s https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/main/deployments/static/nvidia-device-plugin.yml > /tmp/nvidia-device-plugin.yml
user 终端
sed -i ‘/- name: FAIL_ON_INIT_ERROR/a\ - name: DEVICE_DISCOVERY_STRATEGY\n value: “nvml”’ /tmp/nvidia-device-plugin.yml
user 终端
kubectl apply -f /tmp/nvidia-device-plugin.yml
等待并检查状态:
user 终端
sleep 15 && kubectl get pods -n kube-system | grep nvidia-device-plugin
还是有问题。让我检查日志:
user 终端
kubectl logs -n kube-system nvidia-device-plugin-daemonset-gbmpp
检查Pod描述:
user 终端
kubectl describe pod nvidia-device-plugin-daemonset-gbmpp -n kube-system | grep -A 10 “Last State”
还是CDI问题。让我回到最简单的方案 - 完全禁用CDI,使用传统的NVIDIA运行时模式。首先修改containerd配置:
user 终端
sudo sed -i ‘s/default_runtime_name = “nvidia”/default_runtime_name = “runc”/’ /etc/containerd/config.toml
现在修改Device Plugin YAML,显式指定使用nvidia运行时:
user 终端
sed -i ‘/tolerations:/i\ runtimeClassName: nvidia’ /tmp/nvidia-device-plugin.yml
user 终端
kubectl apply -f /tmp/nvidia-device-plugin.yml
重启containerd并等待:
user 终端
sudo systemctl restart containerd && sleep 10 && kubectl get pods -n kube-system | grep nvidia-device-plugin
还是同样的问题。让我检查是否runtimeclass存在:
user 终端
kubectl get runtimeclass
runtimeclass存在。让我检查这个Pod的具体错误:
user 终端
kubectl describe pod nvidia-device-plugin-daemonset-4qgq4 -n kube-system | grep -A 5 “Events:”
让我检查完整的事件和错误:
user 终端
kubectl describe pod nvidia-device-plugin-daemonset-4qgq4 -n kube-system | tail -20
问题还是CDI!让我检查NVIDIA容器运行时的配置,禁用CDI:
\etc\nvidia-container-runtime\config.toml 1 - 20
user 终端
sudo cat /etc/nvidia-container-runtime/config.toml
就是这个配置!NVIDIA容器运行时被配置为CDI模式,但CDI设备没有生成。让我改成传统模式:
user 终端
sudo tee /etc/nvidia-container-runtime/config.toml << EOF
disable-require = false
swarm-resource = “DOCKER_RESOURCE_GPU”
[nvidia-container-runtime]
mode = “auto”
[nvidia-container-runtime.modes]
[nvidia-container-runtime.modes.cdi]
default-kind = “nvidia.com/gpu”
annotation-prefixes = [“cdi.k8s.io/”]
spec-annotation = “cdi.k8s.io/devices”
EOF
现在重启containerd并重新创建Pod:
user 终端
sudo systemctl restart containerd && kubectl delete pod -n kube-system -l name=nvidia-device-plugin-ds
等待并检查:
user 终端
sleep 15 && kubectl get pods -n kube-system | grep nvidia-device-plugin
太好了!Pod现在是Running状态!让我验证GPU资源是否已经注册:
user 终端
kubectl get nodes -o yaml | grep -A 5 nvidia.com/gpu
完美!节点现在报告了GPU资源:
- nvidia.com/gpu.present: “true” - 表示GPU存在
- nvidia.com/gpu: “1” - 表示有1个GPU可用
让我最后验证一下Device Plugin日志确认一切正常:
user 终端
kubectl logs -n kube-system nvidia-device-plugin-daemonset-f7j5m
太好了!Device Plugin现在正常运行,日志显示:
- ✅ 配置加载成功
- ✅ 启动了GRPC服务器用于 nvidia.com/gpu
- ✅ 成功注册了设备插件与Kubelet
- ✅ GPU设备被发现并注册
总结:问题已解决!
根本原因是NVIDIA容器运行时被配置为CDI模式,但系统中没有正确配置CDI设备。通过将运行时改为"auto"模式,Device Plugin现在可以正常使用传统的NVML方式发现GPU。
现在你的K8S集群可以看到GPU资源了,可以开始部署需要GPU的工作负载了!
任务完成
你说得对,我重新理一下思路。既然containerd层面已经验证过GPU正常,那问题应该在K8s的GPU调度机制上。让我重新检查几个关键点:
user 终端
kubectl delete pod gpu-debug-pod
让我重新创建一个正确的测试Pod,使用完整的CUDA镜像而不是基础镜像:
test-gpu-k8s.yaml
- 15 - 0
查看变更
user 终端
kubectl apply -f test-gpu-k8s.yaml
user 终端
kubectl get pod gpu-test-k8s
镜像拉取问题,让我先检查这个镜像是否存在:
user 终端
sudo ctr -n k8s.io images list | grep cuda:12.1.1-runtime
runtime镜像不存在,让我用回之前的base镜像,但用正确的方式测试。既然containerd验证过GPU正常,那现在应该检查K8s设备插件是否正确报告了GPU资源:
user 终端
kubectl get node 10-16-233-177 -o yaml | grep -A10 -B5 “nvidia.com/gpu”
节点确实报告了1个GPU资源。让我检查设备插件的日志,看是否有错误:
user 终端
kubectl logs -n kube-system daemonset/nvidia-device-plugin-daemonset
设备插件运行正常,已成功注册。让我重新用base镜像创建Pod,但先确认镜像路径:
user 终端
sudo ctr -n k8s.io images list | grep cuda | head -5
好的,base镜像存在。让我重新创建Pod,但这次用bash来验证容器内环境:
test-gpu-bash.yaml
- 15 - 0
查看变更
user 终端
kubectl delete pod gpu-test-k8s && kubectl apply -f test-gpu-bash.yaml
user 终端
kubectl get pod gpu-bash-test
user 终端
kubectl logs gpu-bash-test
关键问题确认!容器内没有NVIDIA设备文件,说明NVIDIA容器运行时没有被正确调用。让我检查containerd的runtime配置,确认默认运行时是否设置正确:
user 终端
sudo grep -A20 “runtimes” /etc/containerd/config.toml
看到了问题!containerd配置了nvidia运行时,但默认运行时还是runc。K8s需要知道什么时候使用nvidia运行时。让我检查K8s是否配置了使用nvidia运行时:
user 终端
kubectl get runtimeclass
有nvidia运行时类!让我修改Pod配置来使用这个运行时类:
test-gpu-runtime.yaml
- 16 - 0
查看变更
user 终端
kubectl delete pod gpu-bash-test && kubectl apply -f test-gpu-runtime.yaml
user 终端
kubectl get pod gpu-runtime-test
user 终端
kubectl logs gpu-runtime-test
成功了! 🎉
问题根源找到了:K8s集群需要显式指定 runtimeClassName: nvidia 来使用NVIDIA容器运行时。总结关键发现:
- containerd层面GPU正常 - 之前用ctr测试过
- 设备插件运行正常 - 日志显示已注册,节点报告GPU资源
- 问题在于运行时选择 - 默认的runc不会注入GPU设备,必须使用nvidia运行时类
现在K8s的GPU感知能力验证成功!容器内正确显示了NVIDIA A800 GPU信息。
任务完成
我发现了问题!从日志可以看到关键错误信息:
1User provided device_type of 'cuda', but CUDA is not available. Disabling 2
这表明容器内PyTorch检测不到CUDA,正在使用CPU计算。让我进入容器检查GPU环境:
user 终端
kubectl exec -it progen2-deploy-no-weights-65fd648546-dkd9c – nvidia-smi
容器内没有nvidia-smi命令,说明NVIDIA驱动和CUDA环境没有正确挂载。让我检查当前Pod的配置:
user 终端
kubectl get pod progen2-deploy-no-weights-65fd648546-dkd9c -o yaml | grep -A5 -B5 nvidia
Pod配置显示GPU资源已分配,但容器内缺少NVIDIA工具。让我检查容器内的Python环境和CUDA检测:
user 终端
kubectl exec progen2-deploy-no-weights-65fd648546-dkd9c – python -c “import torch; print(‘CUDA available:’, torch.cuda.is_available()); print(‘CUDA device count:’, torch.cuda.device_count()); print(‘PyTorch version:’, torch.version)”
问题找到了!PyTorch版本是1.12.1+cu116,但CUDA显示不可用。让我检查容器内的CUDA环境变量和库文件:
user 终端
kubectl exec progen2-deploy-no-weights-65fd648546-dkd9c – env | grep -i cuda
CUDA环境变量存在,让我检查容器内的CUDA库文件:
user 终端
kubectl exec progen2-deploy-no-weights-65fd648546-dkd9c – ls -la /usr/local/cuda/lib64/ | head -10
CUDA库文件存在但很少。让我检查容器内的NVIDIA设备文件:
user 终端
kubectl exec progen2-deploy-no-weights-65fd648546-dkd9c – ls -la /dev/nvidia*
问题明确了!容器内缺少NVIDIA设备文件,这是典型的GPU设备未正确挂载问题。让我检查当前Pod的runtimeClass配置:
user 终端
kubectl get pod progen2-deploy-no-weights-65fd648546-dkd9c -o yaml | grep runtimeClass
Pod没有配置runtimeClass!让我检查deployment的配置文件:
progen\docker_progen\progen2-deployment_no_weight.yaml 1 - 50
user\progen\docker_progen
progen\docker_progen\progen2-deploy-no-weights.yaml 1 - 50
问题找到了!deployment配置中缺少 runtimeClassName: nvidia 配置。让我更新deployment文件来修复GPU支持:
progen\docker_progen\progen2-deploy-no-weights.yaml
- 1 - 0
查看变更
现在让我重新应用deployment配置:
user 终端
kubectl apply -f progen2-deploy-no-weights.yaml
让我等待新的Pod启动完成:
user 终端
kubectl get pod -l app=progen2-no-weights -w
新的Pod正在创建中,让我检查详细状态:
user 终端
kubectl describe pod progen2-deploy-no-weights-79df67f774-9phlj | tail -20
新Pod无法调度,因为GPU资源不足。让我检查当前GPU使用情况:
user 终端
kubectl get node -o yaml | grep -A10 -B5 nvidia.com/gpu
节点显示有1个GPU可用,但新Pod无法调度。这是因为旧的Pod还在占用GPU资源。让我先删除旧的Pod:
user 终端
kubectl delete pod progen2-deploy-no-weights-65fd648546-dkd9c
现在让我等待新Pod启动完成:
user 终端
kubectl get pod -l app=progen2-no-weights
让我等待新Pod完全启动:
user 终端
kubectl wait --for=condition=ready pod -l app=progen2-no-weights --timeout=60s
让我检查Pod详细状态和事件:
user 终端
kubectl get pod progen2-deploy-no-weights-79df67f774-9phlj -o wide
很好!新Pod已经运行。现在让我验证GPU环境是否已正确配置:
user 终端
kubectl exec progen2-deploy-no-weights-79df67f774-9phlj – nvidia-smi
太棒了!现在GPU设备已经正确挂载,nvidia-smi可以正常访问。让我验证PyTorch是否能检测到CUDA:
user 终端
kubectl exec progen2-deploy-no-weights-79df67f774-9phlj – python -c “import torch; print(‘CUDA available:’, torch.cuda.is_available()); print(‘CUDA device count:’, torch.cuda.device_count()); print(‘Current device:’, torch.cuda.current_device() if torch.cuda.is_available() else ‘None’)”
完美!CUDA现在可以正常检测到了。让我检查应用日志确认是否开始使用GPU:
user 终端
kubectl logs progen2-deploy-no-weights-79df67f774-9phlj --tail=50
让我检查服务是否正常运行:
user 终端
kubectl get svc progen2-service
让我测试服务是否可访问:
user 终端
curl -s http://10.16.233.177:30090/ | head -10
让我实时查看应用日志来确认GPU使用情况:
user 终端
kubectl logs progen2-deploy-no-weights-79df67f774-9phlj -f --tail=100
现在让我验证完整的部署状态:
user 终端
kubectl get deploy,svc,pod -l app=progen2-no-weights
问题已解决!🎉
根本原因分析:
- 缺失runtimeClass配置 :原deployment配置中缺少 runtimeClassName: nvidia ,导致容器无法正确挂载GPU设备
- GPU设备不可见 :容器内缺少NVIDIA设备文件(/dev/nvidia*),nvidia-smi命令不可用
- PyTorch检测失败 :由于设备文件缺失,PyTorch无法检测到CUDA环境
修复步骤: - ✅ 在deployment配置中添加了 runtimeClassName: nvidia
- ✅ 重新应用配置并重启Pod
- ✅ 验证GPU设备已正确挂载(nvidia-smi可正常访问)
- ✅ 验证PyTorch已能检测到CUDA设备(CUDA available: True)
当前状态:
- 🟢 Pod状态 :progen2-deploy-no-weights-79df67f774-9phlj 运行正常(1/1 Running)
- 🟢 GPU检测 :容器内nvidia-smi可正常访问,显示NVIDIA A800 80GB GPU
- 🟢 PyTorch CUDA :已检测到1个CUDA设备,device_count=1
- 🟢 服务访问 :可通过 http://10.16.233.177:30090/ 正常访问Gradio界面
- 🟢 GPU资源 :Pod已正确分配GPU资源(nvidia.com/gpu: 1)
验证结果:
1# GPU设备检测 2CUDA available: True 3CUDA device count: 1 4Current device: 0 5 6# nvidia-smi输出 7NVIDIA A800 80GB PCIe | 33°C | 0%利用率 | 0MiB/81920MiB内存使用 8
现在ProGen2服务已经正确配置GPU支持,模型计算将使用GPU加速而不是CPU。你可以重新访问 http://10.16.233.177:30090/ 进行蛋白质序列生成,应该能看到GPU开始有计算任务运行了。
任务完成