在k8s环境中,离线部署与使用Topograph

Topograph 离线 K8s 部署与使用指南

目标环境:完全离线的内网 Kubernetes 集群(无外网、无私有镜像仓库)

决策基线(经 grill 确认):

  • Provider = test(先做 PoC 验证,不依赖真实硬件 / 云 IMDS)
  • Engine = k8s(默认引擎,把拓扑写成 Node 标签)
  • 镜像获取 = 节点预加载 (containerd 逐节点 ctr import,无 registry)
  • 加固 = 最小化(不启用 NetworkPolicy / serviceMonitor / ingress)
  • 用途 = 仅 PoC 验证标签落地

1. 说明

1.1 项目简介

Topograph(NVIDIA DSX AI Factory 开源,Apache-2.0)用于发现 Kubernetes 集群的物理网络拓扑(fabric topology) ,并把拓扑信息写成 Node 标签(前缀 fabric.topograph.run/),供拓扑感知调度器(Kueue / Volcano / Slinky 等)消费。

核心抽象是两个概念:

  • Provider :拓扑数据源。离线 PoC 用 test(纯模拟,不需要任何云 API、NetQ、InfiniBand 或真实标签)。
  • Engine :拓扑输出形态。k8s 表示把拓扑写成 K8s Node 标签。

1.2 架构与组件

Helm chart(charts/topograph/,version 1.0.0 / appVersion v1.0.0)部署三个工作负载:

复制代码
                 ┌─────────────────────────────────────────┐
                 │            topograph namespace           │
                 │                                           │
  kube-apiserver │   ┌────────────────┐   /v1/generate       │
   ◄─────────────┤──►│ Topograph API  │   /v1/topology        │
                 │   │   (Deploy x1)  │   /healthz /metrics   │
                 │   │  port 49021    │◄──────────┐          │
                 │   └────────────────┘           │ watch    │
                 │            ▲                   │          │
                 │            │ trigger           ▼          │
                 │   ┌────────────────┐   ┌────────────────┐ │
                 │   │ node-observer  │   │ node-data-     │ │
                 │   │   (Deploy x1)  │   │ broker         │ │
                 │   └────────────────┘   │ (DaemonSet)    │ │
                 │                        └────────────────┘ │
                 └─────────────────────────────────────────┘
                                   │
                                   ▼
                          Node 标签 fabric.topograph.run/*
组件 形态 作用 默认副本
Topograph API server Deployment 核心引擎,写 Node 标签,暴露 API(49021) 1
node-observer Deployment 监听节点/API 变化,触发拓扑再生 1
node-data-broker DaemonSet 采集每节点拓扑属性并写成 annotation 每节点 1

安全基线:镜像以非 root(uid 65532)运行、只读根文件系统、drop ALL capabilities,已满足 K8s restricted Pod Security Standard,离线环境无需额外加固。

1.3 离线关键事实(决定本文写法)

  • 只需 1 个容器镜像 :ghcr.io/dsx-ai-factory/topograph:v1.0.0(Alpine 3.24,含 rdma-core,自带 busybox wget)。
  • 无 init 容器、无 sidecar、无额外依赖镜像 。helm test 复用主镜像(自带 wget),因此 air-gap 下 helm test 也能跑。
  • 镜像名必须保持原 ref :节点预加载后 kubelet 按 image.repository:tag 查找,若改名会导致 ImagePullBackOff。
  • Chart 可整体离线 :chart 源码在仓库 charts/topograph/,可 helm package 成 .tgz 后随镜像一起拷入 air-gap。

2. 准备环境

2.1 拓扑前提(沿用你的离线方法论)

机器 网络 职责 需要的工具
download-machine 有外网 拉取镜像 + chart,导出 tar,中转 docker 或 ctr、helm
operation-machine 仅内网,能 kubectl/helm 到集群 接收 tar,逐节点导入镜像,执行 helm install kubectl、helm、ctr(或 docker)、ssh 到各节点

物理中转:U 盘 / 内网跳板 / 对象存储均可。本文把镜像 tar(topograph-v1.0.0.tar)和 chart(topograph-1.0.0.tgz)从 download-machine 拷到 operation-machine。

2.2 集群与工具版本

  • Kubernetes ≥ 1.27(你的 1.36.4 满足)
  • Helm ≥ 3.10
  • 节点容器运行时 containerd (kubelet 命名空间 k8s.io)
  • kubectl 具备在目标集群创建 namespace、安装 chart、读写 Node 标签的权限(默认 cluster-admin 即可)
  • 节点架构:amd64(镜像提供 linux/amd64;若集群含 arm64 需另行构建)

2.3 离线制品清单

制品 来源 大小量级
topograph-v1.0.0.tar docker save / ctr export of ghcr.io/dsx-ai-factory/topograph:v1.0.0 ~数十 MB
topograph-1.0.0.tgz helm pull 或 helm package charts/topograph < 100 KB
离线 values 配置 内联于本文第 3 节(部署时另存为 values-offline.yaml) ---

3. 配置文件(离线 values)

以下为完整离线 values(已内联本文,不再单独附带文件):

yaml 复制代码
# values-offline.yaml
# Topograph 离线最小化部署覆盖文件
# 决策(经 grill 确认):
#   provider = test        # 先做 PoC 验证,不依赖真实硬件/云 IMDS
#   engine   = k8s         # 默认引擎,把拓扑写成 Node 标签
#   镜像获取 = 节点预加载    # 无私有仓库,containerd 逐节点 import
#   加固     = 最小化       # 不启用 NetworkPolicy / serviceMonitor / ingress
#
# 用法:
#   helm install topograph ./topograph-1.0.0.tgz \
#     --namespace topograph --create-namespace \
#     -f values-offline.yaml

provider:
  name: test

engine:
  name: k8s

image:
  # 必须与原镜像 ref 完全一致,否则节点预加载后 kubelet 仍会尝试拉取
  repository: ghcr.io/dsx-ai-factory/topograph
  tag: v1.0.0
  pullPolicy: IfNotPresent

# 无私有仓库,留空
imagePullSecrets: []

service:
  type: ClusterIP
  port: 49021

replicaCount: 1

verbosity: 3

config:
  requestAggregationDelay: 15s

# 最小化:全部关闭
networkPolicy:
  enabled: false
serviceMonitor:
  enabled: false
ingress:
  enabled: false
gatewayAPI:
  enabled: false

nodeObserver:
  replicaCount: 1

nodeDataBroker:
  enabled: true

tests:
  enabled: true

# 如需让 node-data-broker DaemonSet 也调度到带 NoSchedule 污点的控制平面节点,
# 取消下面注释并填入对应 tolerations:
# nodeDataBroker:
#   tolerations:
#     - operator: Exists
#       effect: NoSchedule
# nodeObserver:
#   tolerations:
#     - operator: Exists
#       effect: NoSchedule

部署时在 operation-machine 上将上述内容保存为 values-offline.yaml(本文不单独附带该文件),后续命令中的 -f values-offline.yaml 即引用它。若目标集群控制平面节点带 NoSchedule 污点、且希望 broker/observer 也跑在 master 上,取消本 values 末尾 tolerations 注释即可。


4. 制品获取(download-machine,有外网)

4.1 获取 Helm chart(二选一)

方式 A --- 从 chart 仓库拉取(推荐,带版本与校验)

bash 复制代码
helm repo add topograph https://dsx-ai-factory.github.io/topograph
helm repo update
helm pull topograph/topograph --version 1.0.0
# 产出:topograph-1.0.0.tgz
# 校验(可选):到 GitHub Releases 比对 SHA-256

方式 B --- 从源码仓库打包(无需 chart 仓库可达)

bash 复制代码
git clone https://github.com/dsx-ai-factory/topograph.git
cd topograph
helm package charts/topograph        # 产出 topograph-1.0.0.tgz

若 download-machine 也无法直连 GitHub,可改用 gh CLI 或网页下载 Release 里的 topograph-1.0.0.tgz 后通过 U 盘中转。

4.2 获取容器镜像

bash 复制代码
# 用 docker(最常见)
docker pull ghcr.io/dsx-ai-factory/topograph:v1.0.0
docker save ghcr.io/dsx-ai-factory/topograph:v1.0.0 -o topograph-v1.0.0.tar

纯 containerd 环境可改为:

bash 复制代码
ctr images pull ghcr.io/dsx-ai-factory/topograph:v1.0.0
ctr images export topograph-v1.0.0.tar ghcr.io/dsx-ai-factory/topograph:v1.0.0

4.3 确认镜像 ref(关键)

bash 复制代码
docker inspect --format '{{index .RepoTags 0}}' topograph-v1.0.0.tar 2>/dev/null || \
  tar -xOf topograph-v1.0.0.tar manifest.json | grep -o '"RepoTags":\[[^]]*' | head -1
# 期望看到:ghcr.io/dsx-ai-factory/topograph:v1.0.0

此 ref 必须与第 3 节 values 里的 image.repository+image.tag 字节级一致。

4.4 中转

把 topograph-1.0.0.tgz、topograph-v1.0.0.tar 拷到 operation-machine(例如 /opt/topograph/);离线 values 已内联于本文第 3 节,部署时在该机另存为 values-offline.yaml。


5. 部署(operation-machine,airgap)

5.1 逐节点导入镜像(containerd)

镜像必须存在于每一个会调度 Topograph Pod 的节点上(API/observer 是 Deployment,broker 是 DaemonSet 跑在所有节点):

bash 复制代码
cd /opt/topograph

for node in node1 node2 node3 master1; do
  echo "==> import on $node"
  # 把 tar 传过去并导入(命名空间 k8s.io 是 kubelet 默认运行时)
  scp topograph-v1.0.0.tar $node:/tmp/
  ssh $node 'ctr -n k8s.io images import /tmp/topograph-v1.0.0.tar && rm -f /tmp/topograph-v1.0.0.tar'
done

验证某节点已就绪:

bash 复制代码
ssh node1 'ctr -n k8s.io images list | grep dsx-ai-factory/topograph'
# 应看到 ghcr.io/dsx-ai-factory/topograph:v1.0.0

docker 运行时 的集群改用:各节点 docker load -i topograph-v1.0.0.tar。

5.2 安装 chart

bash 复制代码
cd /opt/topograph
helm install topograph ./topograph-1.0.0.tgz \
  --namespace topograph --create-namespace \
  -f values-offline.yaml

或纯命令行(不依赖 values 文件):

bash 复制代码
helm install topograph ./topograph-1.0.0.tgz \
  --namespace topograph --create-namespace \
  --set provider.name=test \
  --set engine.name=k8s \
  --set image.tag=v1.0.0 \
  --set image.pullPolicy=IfNotPresent

5.3 确认工作负载起来

bash 复制代码
kubectl -n topograph get pods -o wide
# 期望:topograph-xxxxx (API)        Running
#       topograph-node-observer-xx  Running
#       topograph-node-data-broker-xxxxx (每个节点一个)  Running

6. 访问验证(PoC)

6.1 跑内置 chart 测试(air-gap 友好)

bash 复制代码
helm test topograph -n topograph --timeout 120s
# 探针 pod 复用主镜像内的 wget,探测 Service 的 /healthz 与 /metrics

6.2 确认拓扑标签已写到 Node

Topograph(test provider + k8s engine)会在安装后数秒内自动把模拟拓扑写成 Node 标签:

bash 复制代码
kubectl get nodes --show-labels | grep fabric.topograph.run

列出某节点的全部 topograph 标签:

bash 复制代码
kubectl get node <node-name> --show-labels | tr ',' '\n' | grep topograph.run

前缀说明:fabric.topograph.run/* 为网络 fabric 分层标签;加速器域(若启用)在 accelerator.topograph.run/domain。test 模式下这些是模拟值,仅用于验证流水线。

6.3 查看组件日志

bash 复制代码
kubectl logs -n topograph -l app.kubernetes.io/name=topograph --tail=50

若标签迟迟不出现,先看 API server 日志确认 RBAC 与引擎是否报错。

6.4 API 冒烟测试(可选)

bash 复制代码
kubectl -n topograph port-forward svc/topograph 49021:49021 &
# 健康检查
curl -i http://localhost:49021/healthz
# 指标
curl -s http://localhost:49021/metrics | grep topograph_

7. 使用

7.1 消费拓扑标签做拓扑感知调度

调度器(Kueue / Volcano / kube-scheduler 插件)读取 fabric.topograph.run/* 标签即可感知同 leaf/spine 归属。示例:一个 Pod 请求与某节点同 fabric 域:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: gpu-job
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: fabric.topograph.run/fabric-id   # 实际 key 以集群写入为准
                operator: In
                values: ["<目标节点 fabric-id>"]
          topologyKey: kubernetes.io/hostname
  containers:
    - name: train
      image: registry.example.com/your-train-image:latest

真实 key 名用第 6.2 节的命令从集群实际写入结果中读取,再回填到 topologyKey/values。

7.2 按需触发拓扑生成(/v1/generate 工作流)

默认由 node-observer 自动触发;也可手动触发一次:

bash 复制代码
cat > /tmp/payload.json <<'EOF'
{
  "provider": { "name": "test",
    "params": { "modelFileName": "small-tree.yaml",
                "generateResponseCode": 202, "topologyResponseCode": 200 } },
  "engine": { "name": "k8s" }
}
EOF

uid=$(curl -sS -X POST -H "Content-Type: application/json" \
  -d @/tmp/payload.json http://localhost:49021/v1/generate)
echo "request uid = $uid"

curl -i "http://localhost:49021/v1/topology?uid=${uid}"
# 202 = 仍在处理;200 = 完成并返回拓扑;404 = uid 未知

test provider 用内嵌模型 small-tree.yaml 模拟生成;topologyResponseCode: 200 表示成功返回拓扑。

7.3 指标

GET /metrics(同端口 49021)导出 topograph_version、topograph_http_request_duration_seconds、topograph_request_duration_seconds、topograph_missing_topology、topograph_validation_error_total。如需接入 Prometheus,将第 3 节 values 的 serviceMonitor.enabled 改为 true 并在集群已有 Prometheus 时创建 ServiceMonitor。


8. 排错

现象 根因 处理
Pod ImagePullBackOff 该节点未导入镜像,或 image.tag 与导入 ref 不一致 在该节点 ctr -n k8s.io images import 同 ref 的 tar;核对第 3 节 values 的 image.repository/tag 与 docker save 导出的 ref 完全一致
node-data-broker 未调度到 master master 有 NoSchedule 污点 在第 3 节 values 给 nodeDataBroker.tolerations 加 effect: NoSchedule(文件末尾已给模板)

| 节点上看不到 fabric.topograph.run/* | 引擎未写标签 / RBAC 受限 | kubectl logs -n topograph -l app.kubernetes.io/name=topograph 看报错;确认 chart 安装时 RBAC 已创建(rbac.create 默认 true) |

| helm test 卡住/失败 | 探针 pod 也需主镜像 | 确保主镜像已导入到探针 pod 调度所在节点 |

| 切真实 provider 后拉不到凭证 | 未配 config.credentialsSecret | 用 kubectl create secret generic 挂载 credentials.yaml,并在 values 设 config.credentialsSecret |


9. 后续:从 test 切到真实 Provider

PoC 跑通后,若要发现真实 fabric 拓扑,只需改 provider.name 与相关参数(镜像/部署方式不变):

场景 provider 额外前提
NVIDIA Spectrum-X / Cumulus NetQ netq NetQ API 地址 + token(config.credentialsSecret)
InfiniBand fabric(K8s) infiniband-k8s broker 需 privileged: true(覆盖 podSecurityContext),跑 ibnetdiscover
NVIDIA GPU clique(已有 nvidia.com/gpu.clique) dra GPU Operator 已部署
云集群 aws/gcp/oci/nebius/nscale/lambdai/crusoe 对应云 IMDS / 凭证(不适合纯离线)

切换示例(以 netq 为例):

bash 复制代码
helm upgrade topograph ./topograph-1.0.0.tgz -n topograph \
  -f values-offline.yaml \
  --set provider.name=netq \
  --set 'provider.params.netq.apiUrl=https://netq.example.com' \
  --set config.credentialsSecret=netq-creds

验证方式不变:第 6 节的标签检查与 helm test。

相关推荐
凯歌的博客2 小时前
docker镜像代理
运维·docker·容器
A.说学逗唱的Coke3 小时前
【人工智能专题】PolarDB 深度解析:存算分离到 AI Lakebase,云原生数据库的架构演进与实战指南
数据库·人工智能·云原生
ToddyBear3 小时前
从 Pod 编排到数据互联:基于 K8s 与 Snowflake 打造下一代异构查询桥梁实践
云原生·容器·kubernetes
A-刘晨阳3 小时前
GitLab + ArgoCD 实现 Kubernetes GitOps 自动化部署
运维·人工智能·git·kubernetes·自动化·云计算·argocd
张小凡vip4 小时前
Kubernetes--k8s---了解和使用 ServiceAccount
容器·贪心算法·kubernetes
流星白龙4 小时前
【Docker】13.容器基本操作实战
运维·docker·容器
还卿一钵无情泪18 小时前
Docker 部署Unsloth 绕开环境配置难题
运维·人工智能·docker·ai·容器·nlp·干货
打工仔折腾 AI19 小时前
Docker镜像分层与卷挂载到底怎么工作:一次文件系统层面的实测分析
运维·人工智能·后端·python·docker·容器·性能优化
极客先躯21 小时前
高级java每日一道面试题-2026年01月20日-实战篇[Docker]-如何实现镜像的跨区域复制?
java·运维·docker·容器·架构图