Skip to content

搭建实验环境

环境是什么样的

两台机器分工:本地写和读文档,远程跑实验

text
   本地(macOS / Linux)                    实验主机(Debian 13)
  ┌──────────────────────────┐            ┌──────────────────────────────────┐
  │                          │            │                                  │
  │  learn-ovs/              │            │  ~/labs/learn-ovs/               │
  │   ├── docs/   文档源码    │            │   ├── common/   镜像 + 脚手架     │
  │   │   └─ pnpm dev        │            │   ├── 01-first-bridge/           │
  │   │      localhost:5173  │            │   └── ...                        │
  │   └── labs/   实验源码    │  rsync     │                                  │
  │       └─ ./sync.sh ──────┼───────────▶│  netlab up                       │
  │                          │    ssh     │    └─ containerlab               │
  │                          │            │        └─ docker 容器             │
  │                          │            │            └─ ovs-vswitchd       │
  └──────────────────────────┘            └──────────────────────────────────┘

为什么不在本地跑实验?OVS 的内核 datapath 需要 Linux 的 openvswitch 内核模块,macOS 上没有。而且容器里的 OVS 要用宿主机内核,套一层虚拟机会让"看内核 datapath"这件事变得别扭。

只有一台 Linux 机器也行

如果你就在一台 Linux 机器上干活,把仓库放在那台机器上,跳过 sync.sh,直接进实验目录跑脚本就行。文档站用 pnpm dev --host 起,从别的机器浏览器访问。

实验主机需要什么

依赖用途检查命令
Linux + openvswitch 内核模块OVS 的内核 datapathmodprobe openvswitch && grep -w openvswitch /proc/modules
Docker跑容器docker version
containerlab ≥ 0.75创建容器和 veth 链路containerlab version
netlab ≥ 26.08把拓扑描述翻译成 containerlab 配置netlab version
sudo(免密最省事)加载内核模块、containerlab 建链路sudo -n true
rsync接收 sync.sh 推来的文件rsync --version
当前用户在 clab_adminsdocker不用 root 就能操作groups

安装 netlab 和 containerlab 参考各自官方文档(netlab.toolscontainerlab.dev)。

netlab 常常不在 PATH 里

netlab 一般装在一个 Python 虚拟环境里,登录 shell 默认看不到它:

bash
$ netlab version
bash: netlab: command not found
$ ls ~/.venvs/netlab/bin/netlab
/home/you/.venvs/netlab/bin/netlab 在这儿

实验脚本会自动把 ~/.venvs/netlab/bin 加进 PATH,所以跑实验不受影响。但你手动敲 netlab 命令时需要先:

bash
export PATH=$HOME/.venvs/netlab/bin:$PATH

本地只需要 Node.js 20+ 和 pnpm,用来跑文档站。

三步跑起来

1. 起文档站(本地)

bash
git clone <本仓> learn-ovs
cd learn-ovs
pnpm install
pnpm dev

浏览器打开 http://localhost:5173

2. 把实验推到实验主机

先告诉 sync.sh 目标机器。默认值写在脚本里,改成你自己的:

bash
export OVSLAB_REMOTE=你的用户名@实验主机地址
./labs/sync.sh

输出会逐条列出传了哪些文件:

text
同步 labs/ → [email protected]:labs/learn-ovs/
<f+++++++ sync.sh
cd+++++++ 01-first-bridge/
<f+++++++ 01-first-bridge/start.sh
...
完成。到实验主机上跑:
  ssh [email protected]
  cd labs/learn-ovs/01-first-bridge && ./start.sh

想先看会改什么,加 --dry-run

sync.sh 为什么要排除一堆文件

netlab up 会在实验目录里生成运行时文件:clab.ymlansible.cfghosts.ymlgroup_vars/host_vars/node_files/netlab.snapshot.pickle

这些属于实验主机,不能被本地版本覆盖或删掉 —— 否则正在跑的实验会被打断,stop.sh 也会因为找不到快照而拆不干净。sync.sh 把它们排除在 --delete 之外。

3. 跑第一个实验

bash
ssh 你的用户名@实验主机地址
cd labs/learn-ovs/01-first-bridge
./start.sh

第一次会花两三分钟构建两个容器镜像,之后就是几秒钟的事。

看到这个就成了:

text
== 配置两台主机的地址 ==
  h1 eth1 = 192.168.10.1/24
  h2 eth1 = 192.168.10.2/24

环境就绪。现在 h1 和 h2 物理上都连到了 ovs1,但 ovs1 还没有网桥,
两条线是断的。

然后就可以开始实验 1 了。

实验目录长什么样

text
labs/
├── sync.sh                     把 labs/ 推到实验主机
├── common/
│   ├── ovslab.sh               所有实验共用的一层薄脚手架
│   ├── netlab-defaults.yml     让本教程的实验和别的实验互不干扰
│   └── images/
│       ├── Dockerfile          两个镜像的构建描述
│       └── ovs-entrypoint.sh   容器里怎么拉起 OVS 守护进程
└── 01-first-bridge/
    ├── topology.yml            netlab 拓扑描述
    ├── start.sh                起环境
    ├── solve.sh                参考答案
    ├── verify.sh               检查 + 打印关键状态
    └── stop.sh                 拆环境

四个脚本的分工在本教程怎么用讲过。common/ovslab.sh 只有一百来行,建议扫一遍 —— 你会经常用到里面的 nx 函数。

两个容器镜像

start.sh 会在镜像不存在时自动构建:

镜像扮演装了什么
learn-ovs/host实验里的主机(h1、h2)iproute2pingarpingtcpdumpiperf3jq
learn-ovs/ovs实验里的交换机(ovs1、ovs2)上面这些 加上 openvswitch-switchbridge-utils

刻意分成两个而不是一个通用镜像:这样主机上就是没有 ovs-vsctl 命令,和真实环境的边界一致。你不会不小心在主机上敲交换机的命令还以为生效了。

容器里的 OVS 是怎么起来的

物理机上这一步由 systemd 做(systemctl start openvswitch-switch)。容器里没有 systemd,ovs-entrypoint.sh 直接调 OVS 自带的 ovs-ctl 脚本 —— 和 systemd unit 调的是同一个脚本:

bash
/usr/share/openvswitch/scripts/ovs-ctl start --system-id=random --no-monitor

它负责建库、拉起 ovsdb-server、初始化数据库、拉起 ovs-vswitchd

内核模块由宿主机加载(ovslab.sh 里的 modprobe openvswitch 兜底),容器只是使用宿主机内核里的 datapath。容器由 containerlab 以 privileged 方式运行,所以有权限这么做。

和你机器上其它实验的隔离

netlab 默认把每个实验登记成名叫 default 的实例,同一台机器上只能有一个。如果你机器上已经跑着别的 netlab 实验,直接起本教程的实验会报:

text
It looks like the lab instance 'default' is already running in directory ...

本教程用 netlab 的 multilab 插件绕开这件事,配置在 common/netlab-defaults.yml:给实验分配 id 47,管理网段改成 172.31.47.0/24,docker 网络名改成 nl_mgmt_47。于是:

bash
$ netlab status --all
┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
 id directory status
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
 default /home/you/other-lab started 你原有的实验
 47 /home/you/labs/learn-ovs/01-... started 本教程的实验
└─────────┴──────────────────────────────────┴─────────┘

两套实验可以同时跑,互不影响。

为什么还要覆盖 name

multilab 插件默认会把实验改名成 ml-47,容器就变成 clab-ml-47-h1 这种认不出来的名字。netlab-defaults.yml 里把 name 改回 '{name}'(求值成拓扑自己的名字),容器才是可读的 clab-first-bridge-h1

教程里所有 docker exec 命令都依赖这个命名,别改。

常见问题

netlab: command not found

netlab 在虚拟环境里。见上面的提示框,或者直接跑实验脚本(它们会自己处理 PATH)。

rsync: command not found

实验主机上没装:

bash
sudo apt-get install -y rsync

flock: cannot open lock file .../~/.netlab/lab.lock

netlab 拿到锁文件路径后直接 Path().resolve()不做 ~ 展开common/netlab-defaults.yml 里必须写绝对路径(当前用的是 /tmp/netlab-learn-ovs.lock)。如果你改过这个值,改回绝对路径。

You are not a member of the clab_admins group

bash
sudo usermod -aG clab_admins,docker $USER

然后重新登录让组生效。

无法加载 openvswitch 内核模块

bash
sudo modprobe openvswitch

失败的话检查内核是否带了这个模块:

bash
ls /lib/modules/$(uname -r)/kernel/net/openvswitch/

应该能看到 openvswitch.ko.xz 以及 vport-vxlan.ko.xzvport-gre.ko.xzvport-geneve.ko.xz(第 4 部分的隧道实验需要后面这几个)。

实验起一半失败了,环境是脏的

bash
./stop.sh          # 正常拆

stop.sh 也失败的话,手动清:

bash
export PATH=$HOME/.venvs/netlab/bin:$PATH
netlab status --all                    # 看还登记着什么
netlab status -i 47 --cleanup          # 强行注销本教程的实例
docker ps -a --format '{{.Names}}' | grep '^clab-' | xargs -r docker rm -f

想彻底清掉,包括镜像

bash
./stop.sh
docker rmi learn-ovs/ovs learn-ovs/host

下次 start.sh 会重新构建。

下一步

环境好了,去 实验 1:第一个网桥