Skip to content

Latest commit

 

History

39 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Netpath

网络成长路径 —— 网络方向的在线交互式学习项目。

从「怎么才能看到一手资料」开始,走过 Linux 协议栈上一个包的每一跳,进入 InfiniBand 与 RoCE 的高性能战场,拆开 K8s 容器网络的机制,最后学会把业务需求翻译成端口数、交换机台数和线缆数。

四个分类,就是四步

分类 节数 内容
1 GFW 科学上网与隧道 6 症状分类与诊断、VPS 线路与 anytls 服务端、Mihomo 分流规则与旁路由、HTTP/SOCKS5 代理原理、SSH 端口转发与配置固化(-L/-R/-D、ProxyJump、ControlMaster)、隧道排障闯关
2 ETH 以太网与协议栈 9 一次 curl 的全过程、带宽/PPS/延迟三指标、二三层转发、观测工具箱与闯关、Spine-Leaf 端口账、报文收发路径、TCP 行为、内核栈调优
3 HPC 高性能网络 18 RDMA 原理、InfiniBand、RoCEv2 与无损以太网、Rail 拓扑、策略路由、perftest、NCCL 与闯关、需求拆解与计算网规划选型、PCIe 与 NVLink、GPUDirect、MPI、NVMe-oF、DPU、DPDK
4 K8S K8s 网络 16 K8s 网络模型、CNI 数据平面、Service、MetalLB、Ingress、DNS/策略、地址规划、SR-IOV/次级 CNI、K8s RDMA、Pod 不通闯关、netns/veth 手搓、kube-proxy、eBPF/XDP、可观测性与值班手册

共 4 个分类、15 个小组49 节课(约 26 小时),49 节全部有正文。 动手环节 14 个:8 个实验 + 4 个命令行闯关 + 2 个规划计算器。

一条完整学习路径

目录就是路径 —— 四个分类依次是四步,每步内部按 groups[].lessons 的顺序走, 49 节课全部在线上,没有分岔也不用挑。

早先这里有一张单独维护的 FULL_PATH,把课程重新切成十七段、顺序自成一套。 代价是站里有了两个事实来源:目录一个顺序、路径另一个顺序,每改一节课都要同步两处, 正文里的「上一节 / 下一节」还经常指错人。现在那张表删掉了 —— 它里面真正有价值的是排序决定,这些已经折进各自分类的分组里,跟着课程本身走。

分类之间:由外向内

  1. 能查到资料排第一。 网络方向的一手资料几乎都在海外,这件事不解决,后面每一节能读到的东西都打折。
  2. 门槛低、当天用得上的先来。 SSH 端口转发和代理并在第一步:集群在跳板机后面,连不上什么都做不了。
  3. 值班放最后。 可观测性与值班手册排在整条路的末尾(第 48、49 节),因为它们本来就要覆盖容器网络与高性能网络两层。

分类内部:先概念,再实践,最后原理

每个分类都按同一种节奏推进,小组标题上直接写着 概念:… / 实践:… / 原理:…

讲什么 例子
概念 这是什么、有哪几种、各管一段什么 二层与三层、RoCEv2 与无损以太网、K8s 四条铁律
实践 动手把命令敲一遍、接一台真出问题的机器、算一次账 搭 anytls 出口与 Mihomo 分流、观测工具箱、perftest 与 NCCL
原理 内核和硬件里到底怎么实现的 HTTP 代理与 SOCKS5、一个包的旅程、内核栈调优、PCIe/NVLink、kube-proxy

这条规则最直接的后果是深挖类课程一律往后压:以太网的报文收发路径与内核栈调优挪到工具箱和闯关之后, 高性能网络的 PCIe / NVLink / GPUDirect / DPDK 全部排到打通链路并验收之后, K8s 的 netns 手搓、kube-proxy 三代实现、eBPF/XDP 也让位给「先把网卡插进 Pod」。 科学上网那段同理:HTTP 代理与 SOCKS5 的区别排到 Mihomo 配置之后 —— 先照着把线搭通、把分流配好,再回头看配置里抄过的 socks5socks5h 差在哪。 它们不是入门必需品,是撞到具体瓶颈时才回来读的东西。

一处看着像例外、其实不是的:科学上网那段的 SSH 端口转发 是实验课,却排在 原理 组里 —— 因为 ssh -D 开的就是一个 SOCKS5 代理,ProxyCommand 又要靠代理知识才配得对, 它本质上是「把代理原理换一种方式再做一遍」,跟 HTTP 代理与 SOCKS5 是同一段。

PREREQ 里的每一条前置依赖都落在路径的更早位置,按顺序走不会遇到「建议先学」指向后面的课 (bun run check 会校验这一点,顺便查分组里有没有漏课或重复引用)。 课程另按 DEPTH 标了「入门 / 深入」两端,标「深入」的赶时间可以先跳过。

首页版式

storpath 对齐:框架段 → 入口卡(已完成 N/49 + 进度条 + 「开始学 · 第 1 节 …」)→ 一步一张卡的阶梯 → 结尾一句话。

每步一张卡:卡头是分类徽标 + 「第 N 步」 + 分类名(链到 /tracks/<id>)+ 副标题 + 节数时长 + 本步进度, 下面一句话说明这一步解决什么;步内每行课是步内序号 + 标题 + 一句话说明, 右侧最多一个标签(实验 / 闯关 / 规划,纯读的课若标了 深入 则占这个位置)加时长。

课程页的导航跟着这条线走:「下一课 / 上一课」跨分类连续,右栏是整条路径按四步分组, 顶部提示条显示「第 N / 49 节 + 当前分类」。

进度存在浏览器 localStorage。 每次改动分类划分 trackId 都会变, progress.ts 里按版本各存了一张一次性迁移表(v1 → v2 → v3),老的完成记录会被搬过来: 合并掉的课映射到承接它的那一节,整节删除的(VPN 组网)直接丢弃。

线上地址:https://netpath.wutz.dev

交互形式

  • 检查点(Quiz) —— 随堂单选/多选,选错给针对性反馈,答对写入本地进度
  • 路径推演(PacketPathExplorer) —— 9 个场景(主机收发、同节点/跨节点 Pod、ClusterIP、 LoadBalancer、RoCE WRITE、GPUDirect RDMA、SSH 动态转发), 逐跳展开,每跳都给出观测命令典型故障方式
  • 配图(Figure) —— 引用外部示意图时统一走这个组件,图注与来源链接位置固定,不给漏署名留余地
  • 命令行闯关(Terminal) —— 模拟终端,预置真实的 ethtool -Ssoftnet_stat、NCCL 日志输出, 按目标一步步定位根因;支持 goals / hint / help / 命令历史
  • 规划计算器(Planner) —— 两个:
    • 以太网 Spine-Leaf 端口账(leaf/spine 台数、收敛比、线缆数、余量)
    • 计算网 Rail-Optimized 布线账(rail、leaf/spine、线缆、对分带宽), 输入 31 节点 / 8 卡 / 64 口交换机时结果与 DGX SuperPOD H200 参考架构 Table 4 完全一致
  • 进度追踪 —— 存 localStorage,无账号体系,换设备不同步

技术栈

storpath / storplan 保持一致:

  • TanStack Start / Router —— 全栈 React 框架 + 类型安全文件路由
  • MDX —— 课程正文,可直接内嵌交互组件
  • Shiki —— 构建期代码高亮
  • Tailwind CSS 4 —— 样式
  • Cloudflare Workers —— 部署

快速开始

bun install
bun run dev        # http://localhost:3002
bun run build
bun run typecheck
bun run check      # 大纲自检:分组完整性 + 前置依赖不指向后面的课
bun run deploy     # 手工部署到 Cloudflare Workers

持续部署

Cloudflare Workers Builds,无需在 GitHub 里存密钥。 Dashboard → Compute (Workers) → netpath → Settings → Build → Connect, 授权 GitHub App 并选中 wutz/netpath,构建命令填 bun run build,部署命令填 bunx wrangler deploy。 之后推送到 main 即自动部署。

Workers Builds 的仓库连接依赖 GitHub App 的 OAuth 授权,只能在 Dashboard 上完成,wrangler CLI 没有对应命令。

项目结构

netpath/
├── src/
│   ├── lib/
│   │   ├── curriculum.ts       # 课程大纲:全站唯一数据源
│   │   ├── content.ts          # MDX 正文加载
│   │   ├── progress.ts         # 学习进度(localStorage)
│   │   ├── netunits.ts         # Gbps/GB/s/PPS/BDP 换算,口径全站统一
│   │   ├── packet-path.ts      # 10 个报文路径场景的逐跳数据
│   │   ├── eth-plan.ts         # 以太网 Spine-Leaf 三笔账
│   │   └── fabric-plan.ts      # Rail-Optimized 计算网布线账(含 SuperPOD 对照表)
│   ├── components/
│   │   ├── Callout.tsx             # note / tip / warn / trap 四种提示框
│   │   ├── Quiz.tsx                # 随堂检查点
│   │   ├── Terminal.tsx            # 命令行闯关模拟器
│   │   ├── Figure.tsx              # 带出处署名的配图
│   │   ├── PacketPathExplorer.tsx  # 报文路径逐跳推演
│   │   ├── EthernetPlanner.tsx     # 以太网端口账计算器
│   │   ├── FabricPlanner.tsx       # 计算网布线账计算器
│   │   ├── mdx-components.tsx      # MDX 全局组件表
│   │   └── lesson-context.ts       # 当前课程 key,供交互组件写进度
│   ├── content/                # 课程正文
│   │   ├── gfw/                # 6 节 · 科学上网与隧道
│   │   ├── ethernet/           # 9 节 · 以太网与协议栈
│   │   ├── hpc/                # 18 节 · 高性能网络
│   │   └── k8s/                # 16 节 · K8s 网络
│   ├── routes/
│   │   ├── __root.tsx
│   │   ├── index.tsx                    # 首页:完整学习路径(四步,一步一张卡)
│   │   ├── tracks.$trackId.tsx          # 分类详情
│   │   ├── learn.$trackId.$lessonId.tsx # 课程页
│   │   └── labs.tsx                     # 实验与闯关索引
│   ├── router.tsx
│   └── styles.css
├── vite.config.ts
└── wrangler.toml

新增一节课

  1. src/lib/curriculum.ts 对应分类里加一条 Lesson,写清 objectivesoutline
  2. 把它的 id 加进某个 groups[].lessons —— 学习顺序由这里决定,Track.lessons 只是课程池。 按「先概念、再实践、最后原理」挑分组:讲清概念的进 概念:…,动手敲命令或算账的进 实践:…, 拆内核与硬件实现的进 原理:… (零经验也能读的加进 DEPTHintro,需要背景才看得懂的标 deep
  3. 有强依赖时在 PREREQ 里登记,课程页会显示「建议先学」;bun run check 会拦住指向后面的依赖
  4. 新增课程可先留 'planned' —— 课程页会自动渲染大纲占位,路径图上标记为「大纲」
  5. 正文写好后建 src/content/<trackId>/<lessonId>.mdx,把状态改成 'ready'
  6. 不需要再登记到别处 —— 分组顺序就是学习顺序,加进 groups[].lessons 它就在首页那条线上了

调整学习顺序只需改 groups[].lessons 的排列,不用挪动 Lesson 对象。

两个 MDX 陷阱:

  • JSX 属性值用双引号包裹,属性内部不要再出现半角双引号(用 「」 代替)
  • 正文里不要出现 <80% 这种「小于号紧跟字符」的写法,MDX 会当成 JSX 标签解析。写成「低于 80%」

MDX 里可以直接使用交互组件,无需 import:

<Callout type="trap" title="新人常踩的坑">
MTU 必须端到端一致,任何一跳不一致都会导致大包被丢弃。
</Callout>

<Quiz
  id="net-1"
  question="一台 leaf 有 48 个 25G 下行口和 4 个 100G 上行口,收敛比是多少?"
  options={[
    { text: '3:1', correct: true },
    { text: '12:1', feedback: '收敛比按带宽算,不按端口数算。' },
  ]}
  explain={<>下行 1200 Gbps,上行 400 Gbps,即 3:1。</>}
/>

<PacketPathExplorer only={["host-tx", "host-rx"]} />
<EthernetPlanner />
<FabricPlanner />

<Figure
  src="https://example.com/diagram.png"
  alt="示意图"
  caption="一句话说明这张图在讲什么。"
  source="作者 · 站点名"
  href="https://example.com/original-article"
/>

引用外部图片一律用 Figure 并填 sourcehref,把出处指向原文而不是图片本身。

命令行闯关:给命令加 goal 字段即成为闯关目标,全部达成后自动记录通过。 aliases 可以接受等价写法,减少"命令没预置"的挫败感。

<Terminal
  id="slow-host-quest"
  host="root@k8s-work-103"
  commands={[
    { cmd: 'ethtool bond0', goal: '确认链路速率协商正常', hint: '第一层永远是接口与链路', output: `...` },
    { cmd: 'ethtool -S bond0', aliases: ['ethtool -S bond0 | grep -i drop'], output: `...` },
  ]}
/>

内容来源

后续可做

  • 再加三个闯关:Pod 之间不通、MTU 黑洞、隧道断点定位
  • 拓扑图交互组件:拖动节点数看 leaf/spine 布线图变化
  • 深色模式(Shiki 已按双主题编译,接一个切换即可)
  • 全站搜索

About

系统与集群网络在线交互式学习路径:Linux 协议栈与报文路径 → K8s 容器网络 → PCIe/NVLink 与 InfiniBand/RoCE → 以太网与计算网规划 → 代理与隧道

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages