LogoTensorFusion 文档
LogoTensorFusion 文档
首页

快速开始

TensorFusion 概览在 Kubernetes 安装在虚拟机/服务器安装(K3S)Helm 快速安装在宿主机/虚拟机安装TensorFusion 架构

应用操作

创建 AI 应用注解使用场景配置自动扩缩容迁移现有应用最佳实践

自定义AI基础设施

生产级部署指南QoS 级别与计价云厂商集成(BYOC)管理许可证

维护与优化

组件更新配置告警GPU 热迁移预加载模型优化 GPU 效率

故障排除

问题处理手册链路追踪/性能分析查询指标和日志

参考

对比

与 NVIDIA vGPU 对比与 MIG/MPS 对比与趋动科技对比与 NVIDIA Run:ai 对比与 HAMi 的对比

问题处理手册

按现象排查 TensorFusion 的常见问题,从 GPU 没被发现、Pod 一直 Pending 到限额不生效

本手册按现象组织。找到与你看到的情况对应的小节,先执行检查命令,再按匹配的原因处理。文中的命令都假设 Helm release 和命名空间均为 tensor-fusion-sys,不一样的话请自行替换。

先收集基本信息

大多数问题都能从下面五条命令的输出里看出来,先把它们跑一遍:

kubectl get tensorfusioncluster,gpupool,gpunode,gpu
kubectl get pods -n tensor-fusion-sys -o wide
kubectl logs -n tensor-fusion-sys deploy/tensor-fusion-sys-controller -c controller --tail=200
kubectl logs -n tensor-fusion-sys hypervisor-<node> --all-containers --tail=200
kubectl describe pod <pod> -n <namespace>

正常的安装应该是这样的:集群和资源池都是 Running;每个 GPU 节点有一个 Running 的 GPUNode 和一个 hypervisor-<node> Pod;每张卡有一个 GPU 资源,带总量和可用量。

controller 反复重启

检查

kubectl get pods -n tensor-fusion-sys -l tensor-fusion.ai/component=operator
kubectl logs -n tensor-fusion-sys deploy/tensor-fusion-sys-controller -c controller --previous
kubectl describe pod -n tensor-fusion-sys -l tensor-fusion.ai/component=operator
现象原因处理
日志最后是 unable to load global config fileHelm values 里的 dynamicConfig 不合法修正 values 后执行 helm upgrade
日志最后是 invalid isolation mode policycontroller.isolationModePolicy 的值不受支持改成 dynamic 或 static
Pod 停在 ContainerCreating,事件里提到 Secret tensor-fusion-webhook-secretwebhook 证书没有生成。证书由 Helm hook job 创建,而用 helm template 加 kubectl apply 安装时 hook 不会执行用 helm upgrade --install 安装或升级
升级之后马上出现“未知的 kind 或字段”一类报错CRD 比 controller 旧。Helm 不会升级 CRD手动 apply chart 里的 CRD,见组件更新
上一次退出状态是 OOMKilled内存上限对当前集群规模来说太小调大 controller.resources.limits.memory

没有发现 GPU

现象: kubectl get gpu 为空或缺卡,或者资源池的总量为零。

设备发现是一条链:打了标签的 Kubernetes Node 对应一个 GPUNode,GPUNode 对应一个 hypervisor Pod,hypervisor 再把每张卡上报成一个 GPU。从前往后找到第一个断掉的环节。

检查

kubectl get nodes -l nvidia.com/gpu.present=true
kubectl get gpunode
kubectl get pods -n tensor-fusion-sys -l tensor-fusion.ai/component=hypervisor -o wide
kubectl get gpu -o custom-columns='NAME:.metadata.name,MODEL:.status.gpuModel,PHASE:.status.phase,USED_BY:.status.usedBy,CAPACITY:.status.capacity'
现象原因处理
第一条命令里没有这个节点节点缺少 TensorFusion 用来筛选的标签。controller 只监听匹配 initialGpuNodeLabelSelector(默认 nvidia.com/gpu.present=true)的节点,资源池再通过 nodeManagerConfig.nodeSelector 选节点给节点打标签:kubectl label node <node> nvidia.com/gpu.present=true。或者把 initialGpuNodeLabelSelector 和 cluster.pool.nodeSelectorKey 改成 GPU 节点上已有的标签
节点有标签,但没有 GPUNode资源池的节点选择器没有选中它对比 kubectl get gpupool <pool> -o jsonpath='{.spec.nodeManagerConfig.nodeSelector}' 和节点的标签
有 GPUNode,但没有 hypervisor Pod,或者 Pod 不是 Runninghypervisor 起不来见 hypervisor Pod 未就绪
hypervisor 是 Running,但没有 GPUhypervisor 没有找到设备:厂商驱动没装,或者容器里看不到驱动在节点上执行 nvidia-smi。查看 hypervisor 的日志和设备列表,方法见查看节点上的 hypervisor
有 GPU,但 USED_BY 不是 tensor-fusion这张卡被以原生方式申请 GPU 的 Pod 占着,例如申请了 nvidia.com/gpu。TensorFusion 不会分配这样的卡把那个工作负载迁到 TensorFusion,见迁移现有应用;或者把这张卡留给它
CAPACITY 里的 TFLOPS 缺失或明显不对这个 GPU 型号不在厂商的 ProviderConfig 里,算力是运行时估算的在 Helm values 的 providerConfigs.nvidia.hardwareMetadata 里补上这个型号,fullModelName 必须与 MODEL 列完全一致

hypervisor Pod 未就绪

现象: hypervisor-<node> 处于 Init、CrashLoopBackOff 或 Pending;GPUNode 一直是 Pending;或者 Pod 调度失败,提示 node tensor-fusion.ai/index_0 allocatable is <= 0, hypervisor likely unhealthy。

检查

kubectl describe pod -n tensor-fusion-sys hypervisor-<node>
kubectl logs -n tensor-fusion-sys hypervisor-<node> --all-containers --tail=200
kubectl logs -n tensor-fusion-sys hypervisor-<node> --all-containers --previous
kubectl describe gpunode <node>
现象原因处理
卡在 init 容器 init-runtime 或 init-shm,状态为 ImagePullBackOffGPU 节点拉不到厂商 provider 镜像(providerConfigs.nvidia.images.middleware)或 hypervisor 镜像见镜像拉取失败
卡在 init 容器 toolkit-validation,日志是 waiting for nvidia container stack to be setupcontroller.compatibleWithNvidiaContainerToolkit 为 true,hypervisor 在等 /run/nvidia/validations/toolkit-ready 这个文件,它由 NVIDIA GPU Operator 写入修复节点上的 GPU Operator。没有使用 GPU Operator 的话,把这个值设为 false
日志里有 failed to load accelerator libraryTF_ACCELERATOR_LIB_PATH 指向的厂商库不存在,或者容器里看不到 GPU 驱动库确认节点上 nvidia-smi 正常,并且已经为容器运行时安装、配置好 NVIDIA Container Toolkit
Pod 被反复删除重建,GPUNode 上有 HypervisorCrashLoopRecreate 事件容器重启达到 5 次(dynamicConfig.hypervisorMaxCrashCount)后,controller 会重建 hypervisor Pod赶在 Pod 被替换之前用 --previous 看日志,按日志里的崩溃原因处理
controller 日志显示创建 Pod 被 Pod Security 拒绝hypervisor 需要特权模式、host PID 和 host 网络,而命名空间强制了更严格的 Pod Security 级别给 TensorFusion 所在命名空间放开到 privileged 级别
日志显示 HTTP 端口已被占用hypervisor 使用主机网络,节点上有别的进程占了 8001 端口释放该端口;或者在资源池上设置 componentConfig.hypervisor.portNumber,并重建该资源池的工作负载

处理之后,Pod 变为 Running,GPUNode 也随之变为 Running。

webhook 没有注入 Pod

现象: Pod 在运行,但看到的是整张 GPU,或者看不到 GPU,也没有 TensorFusion 的 init 容器。

检查

kubectl get pod <pod> -n <namespace> --show-labels
kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.schedulerName}{"\n"}{.spec.initContainers[*].name}{"\n"}'
kubectl logs -n tensor-fusion-sys deploy/tensor-fusion-sys-controller -c controller | grep "Mutating pod"

被注入的 Pod 带有 tensor-fusion.ai/gpupool=<pool> 标签。使用本地 GPU 的 Pod,调度器是 tensor-fusion-scheduler;soft 模式下有 init-soft-limiter 和 tf-soft-preload-0 两个 init 容器;使用远程 GPU 或 hard 隔离时有 inject-lib;shared 和 partitioned 的 Pod 没有 init 容器。

原因处理
没有 tensor-fusion.ai/enabled: "true" 标签。webhook 只会收到带这个标签的 Pod加到 spec.template.metadata.labels 下
标签或注解写在了 Deployment 自身的 metadata 上,而不是 Pod 模板上挪到 spec.template.metadata 下
Pod 是在加标签之前创建的。webhook 只在 Pod 创建时起作用重建 Pod:kubectl rollout restart deployment/<name>
tensor-fusion.ai/inject-container 写了一个不存在的容器名。这种情况下 webhook 直接跳过,不报错改成正确的容器名
设置了 tensor-fusion.ai/enabled-replicas,而这个工作负载已经有这么多 Pod 用上了 TensorFusion灰度期间的正常行为。想覆盖更多副本就调大这个数
webhook 没有注册kubectl get mutatingwebhookconfiguration tensor-fusion-sys-mutating-webhook 应该能查到。查不到就重新执行 helm upgrade

创建 Pod 时被 webhook 拒绝

现象: Deployment 的 Pod 数少于副本数。报错在 ReplicaSet 上,不在 Pod 上。

检查

kubectl describe replicaset -n <namespace> -l <your-pod-label>
报错内容包含原因处理
gpu pool(...) does not existtensor-fusion.ai/gpupool 指定的资源池不存在;或者没写这条注解,而集群里也没有默认资源池从 kubectl get gpupool 里选一个名字;或者在 TensorFusionCluster 里给某个资源池设置 isDefault: true
tflops request is not setPod 没有声明资源请求加上 tensor-fusion.ai/tflops-request 或 tensor-fusion.ai/compute-percent-request,以及 tensor-fusion.ai/vram-request
parse tf resources某条注解的值不合法对照注解参考
failed calling webhook "mpod.tensor-fusion.ai"没有就绪的 controller 副本,或者证书无效。webhook 的失败策略是 Fail,这期间带标签的 Pod 都创建不了见 controller 反复重启

Pod 一直 Pending

现象: 工作负载的 Pod,或者远程 GPU 工作负载的 worker Pod,一直没有被调度。

先找出真正需要 GPU 的那个 Pod。使用本地 GPU 时就是应用 Pod 本身;使用远程 GPU 时,应用 Pod 等的是 worker Pod,它由 controller 在同一个命名空间里创建:

kubectl get tensorfusionworkload,tensorfusionconnection -n <namespace>
kubectl get pods -n <namespace> -l tensor-fusion.ai/component=worker

检查

kubectl describe pod <pending-pod> -n <namespace>
kubectl get gpu -o custom-columns='NAME:.metadata.name,MODEL:.status.gpuModel,PHASE:.status.phase,USED_BY:.status.usedBy,MODE:.status.isolationMode,ACTIVE_MODE:.status.activeIsolationMode,AVAILABLE:.status.available'
kubectl get gpuresourcequota -n <namespace>
事件或提示原因处理
GPUQuotaOrCapacityNotEnough没有哪张 GPU 的可用 TFLOPS 和显存够这次请求用,或者命名空间的 GPUResourceQuota 已经用完把请求值和 AVAILABLE 列对比。调低请求、腾出容量、加 GPU 节点,或者调大配额
每个节点都提示 GPU not fit有容量足够的 GPU,但都没通过其他筛选条件:gpu-model、gpu-indices、厂商或隔离模式把这些注解和 MODEL、MODE、ACTIVE_MODE 列对照。一张 GPU 同一时间只服务一种隔离模式
Pod 申请的是 tensor-fusion.ai/isolation: sharedshared 占用整张 GPU,需要一张上面没有任何分配的卡腾出一张卡,或者改用 soft
hypervisor likely unhealthy该节点的 hypervisor 挂了见 hypervisor Pod 未就绪
gang scheduling timeout,或者有 GangWaitingForMembers、GangSchedulingTimeout 事件Pod 属于一个 gang,成员没法同时全部放下为整组腾出容量,或者调低 tensor-fusion.ai/gang-min-members
只有 Kubernetes 的常规原因,例如污点、节点亲和性、CPU 或内存不足GPU 放得下,节点放不下和普通 Pod 一样处理:调整容忍、选择器或 CPU、内存请求
完全没有调度事件Pod 用的是 tensor-fusion-scheduler,它运行在 controller 进程里,而当前没有就绪的 controller 副本见 controller 反复重启

资源池的分配失败次数记录在 tf_system_metrics 表里,见查询指标和日志。

Pod 卡在 Init 阶段

现象: Pod 已经调度到节点,但一直是 Init:... 或 Init:ImagePullBackOff。

检查

kubectl describe pod <pod> -n <namespace>
kubectl logs <pod> -n <namespace> -c <init-container>
init 容器原因处理
init-soft-limiter拉不到厂商 provider 镜像见镜像拉取失败
inject-lib拉不到 client 镜像同上
tf-soft-preload-0这个容器用的是你的应用镜像,需要镜像里有 /bin/sh、cat 和 chmod。distroless 和 scratch 镜像没有这些换一个带 shell 的应用镜像,或者改用别的隔离模式

限额没有生效

现象: soft 隔离的工作负载用掉的显存或算力超过了限制值,或者容器里的 nvidia-smi 显示的是整张卡的显存。

检查

kubectl exec <pod> -n <namespace> -c <container> -- sh -c '
  cat /etc/ld.so.preload
  env | grep -E "^TF_(ISOLATION_MODE|SHM_PATH)="
  ls -l "$TF_SHM_PATH"
  nvidia-smi'

限额正常生效时:/etc/ld.so.preload 里有 /tensor-fusion-limiter/libcuda_limiter.so;TF_ISOLATION_MODE 是 soft;TF_SHM_PATH 指向的文件存在;nvidia-smi 显示的显存总量就是显存限制值。

现象原因处理
没有 /etc/ld.so.preload,或者里面没有 limiterPod 没有被注入,或者隔离模式不是 soft见 webhook 没有注入 Pod
隔离模式是 shared设计如此。shared 分配整张卡,不做任何限制需要限制时用 soft 或 hard
TF_SHM_PATH 指向的文件不存在节点上的 hypervisor 还没有为这个 Pod 写入限额先让 hypervisor 恢复正常,再重建 Pod
上面几项都正常,但进程没有被限制进程没有加载 /etc/ld.so.preload。静态链接的二进制和基于 musl 的镜像(如 Alpine)会这样换成基于 glibc 的镜像。可以在应用进程的 /proc/<pid>/maps 里查 limiter 是否被加载来确认
算力用量短时间超过限制值soft 模式用限流器限制算力,短时突发会放行,平均值收敛到限制值需要严格封顶时用 hard 隔离

清空 LD_PRELOAD 并不能关掉 limiter,因为它是通过 /etc/ld.so.preload 加载的。

hard 隔离的限额由 worker 执行。确认 worker 容器上有 TF_CUDA_SM_PERCENT_LIMIT 和 TF_GPU_MEMORY_LIMIT:

kubectl get pod <worker-pod> -n <namespace> -o yaml | grep -A1 -E 'TF_CUDA_SM_PERCENT_LIMIT|TF_GPU_MEMORY_LIMIT'

CUDA 显存不足

现象: 应用报 CUDA out of memory 或 CUDA_ERROR_OUT_OF_MEMORY。

检查

kubectl exec <pod> -n <namespace> -c <container> -- nvidia-smi
kubectl get pod <pod> -n <namespace> -o jsonpath='{.metadata.annotations}'
kubectl describe pod <pod> -n <namespace>
现象原因处理
容器里 nvidia-smi 显示用量已到显存限制值,而物理卡上还有空闲显存工作负载触到了自己的 tensor-fusion.ai/vram-limit。soft 模式下 limiter 会让这次分配以显存不足失败调大 vram-request 和 vram-limit,减小 batch size 或上下文长度,或者开启自动扩缩容
刚启动、还没真正干活就报错框架一上来就预留固定比例的显存在框架里限制预留量。TensorFlow:设置 TF_FORCE_GPU_ALLOW_GROWTH=true。vLLM:调低 --gpu-memory-utilization
工作负载没到自己的限制值,但物理卡已经满了这张卡上的工作负载显存限制值高于请求值,加起来超过了卡的实际显存需要保证显存的工作负载,把 vram-request 设成和 vram-limit 一样
Pod 是 OOMKilled,或者被驱逐并提示 The node was low on resource: memory这是主机内存不足,不是显存按模型加载时的实际需要,给容器设置内存请求和限制

CUDA 或 NVML 库报错

现象: NVML Function Not Found;libnvidia-ml.so.1: cannot open shared object file;worker 断言失败,例如 cuInit_fn != nullptr;或者 PyTorch 报 device >= 0 && device < num_gpus INTERNAL ASSERT FAILED。

这些报错说明进程找不到驱动的 libcuda.so.1 或 libnvidia-ml.so.1,或者找到的路径和 TensorFusion 预期的不一样。

检查:先在 GPU 节点上执行,再到出错的容器里执行:

nvidia-smi
ldconfig -p | grep -E 'libcuda.so.1|libnvidia-ml.so.1'
cat /etc/ld.so.preload
原因处理
节点上没有安装驱动,或驱动没有加载lsmod | grep nvidia 没有输出。安装 NVIDIA 驱动
节点上有驱动库,容器里没有为容器运行时安装并配置 NVIDIA Container Toolkit
库所在的目录和 worker 预期的不一样。chart 的 worker 模板指向 /usr/lib/x86_64-linux-gnu,而 RHEL 系发行版用的是 /usr/lib64在出错的容器上设置 TF_CUDA_LIB_PATH 和 TF_NVML_LIB_PATH,指向容器里真实存在的 .so.1 路径。不要用带驱动版本号的路径,驱动一升级它就变了
PyTorch 一个设备都看不到应用进程没有加载 TensorFusion 的库,见 webhook 没有注入 Pod

远程 GPU 工作负载

远程 GPU 工作负载的应用 Pod 通过 TensorFusionConnection 连到 worker Pod。先看两端的状态:

kubectl get tensorfusionconnection -n <namespace>
kubectl logs <worker-pod> -n <namespace> --tail=200
现象原因处理
connection 里没有 worker 或连接地址worker Pod 还没跑起来见 Pod 一直 Pending
worker Pod 反复重启先看它的日志。想看更多细节就调高日志级别,见链路追踪/性能分析按日志里的原因处理。寻求帮助时把日志一起带上
应用报 CUDA driver error: named symbol not found应用调用了远程模式不支持的 CUDA API。worker 日志会写出是哪个,例如 call api=cuMemAddressReserve failed。PyTorch 设置了 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True 时就会触发这一个去掉触发该调用的设置,或者让工作负载使用本地 GPU
应用报 Invalid Memory Address与 worker 的显存管理器之间的一种少见冲突给这个工作负载加注解 tensor-fusion.ai/disable-features: mem-manager,关掉显存管理器。依赖它的功能对该工作负载不再可用

镜像拉取失败

TensorFusion 的镜像在两类节点上拉取:controller、Alertmanager 和 GreptimeDB 的镜像在这些 Pod 所在的节点上拉;hypervisor、厂商 provider、client 和 worker 的镜像在 GPU 节点和业务工作负载所在的节点上拉。

检查

kubectl get pods -A | grep -E 'ImagePullBackOff|ErrImagePull'
kubectl describe pod <pod> -n <namespace>
原因处理
集群访问不了 Docker Hub 等公共镜像仓库在每个节点的容器运行时里配置镜像加速。或者把镜像同步到自己的仓库,再用 Helm values 覆盖:controller.image.repository、cluster.hypervisorImage、providerConfigs.nvidia.images.*、greptime.image.repository、alert.image.repository
集群在中国大陆加上 values-cn.yaml,见在 Kubernetes 安装
私有仓库需要凭据在 Helm values 里设置 imagePullSecrets

申请 nvidia.com/gpu 的 Pod

TensorFusion 不会注册 nvidia.com/gpu 资源。申请了它但没有 TensorFusion 标签的 Pod,webhook 不做任何处理;只有装了 NVIDIA device plugin,这样的 Pod 才能被调度:

helm upgrade --install --create-namespace --namespace nvidia-device-plugin \
  --repo https://nvidia.github.io/k8s-device-plugin/ nvdp nvidia-device-plugin

想把这类工作负载改由 TensorFusion 管理,见迁移现有应用。

可以忽略的报错

Error in cpuinfo: prctl(PR_SVE_GET_VL) failed:ARM 容器镜像跑在不支持 SVE 指令的 CPU 上时会出现,例如在 macOS 上。大多数情况下可以忽略。

获取帮助

以上都对不上的话,可以到 github.com/NexusGPU/tensor-fusion 提 issue,或者发邮件到 support@tensor-fusion.com,并附上先收集基本信息里那几条命令的输出。分享日志之前,请去掉其中的 token、密钥和内网地址。

需要更深入的排查手段,见链路追踪/性能分析和查询指标和日志。

优化 GPU 效率

先量出资源池分配了多少、实际用了多少,再调整工作负载的资源配置、让负载排得更紧凑,并释放空闲节点

链路追踪/性能分析

追踪 TensorFusion 在工作负载内部做了什么,查看节点上 hypervisor 的状态,分析 CUDA kernel 的性能

目录

先收集基本信息
controller 反复重启
没有发现 GPU
hypervisor Pod 未就绪
webhook 没有注入 Pod
创建 Pod 时被 webhook 拒绝
Pod 一直 Pending
Pod 卡在 Init 阶段
限额没有生效
CUDA 显存不足
CUDA 或 NVML 库报错
远程 GPU 工作负载
镜像拉取失败
申请 nvidia.com/gpu 的 Pod
可以忽略的报错
获取帮助