Kubo 三节点集成测试(3nodetest)实战:基于 Docker 的 bootstrap/server/client 端到端内容分发验证
【免费下载链接】kuboIPFS implementation in Go: a daemon that stores and serves content-addressed data, with a CLI, HTTP Gateway, and RPC API项目地址: https://gitcode.com/GitHub_Trending/ku/kubo
本文以 test/3nodetest/README.md 为核心,深入讲解 Kubo(IPFS 的 Go 实现)仓库内置的三节点集成测试:如何使用 Docker 编排一个「bootstrap 引导节点 + server 提供节点 + client 拉取节点」的最小内容分发网络,并自动完成文件添加、CID 共享与跨节点取回校验。读完本文,你将掌握这套测试的完整拓扑、四个容器的职责划分、make setup/fig build/fig up的完整执行链路,以及它与 Go 单元级集成测试TestThreeLeggedCatTransfer的对应关系,可用于复现和改造自己的多节点 IPFS 测试环境。
一、测试目标:最小化的“三腿猫”内容分发场景
该测试的本质是一个three-legged cat(三腿猫)场景:由三个节点构成一条完整的数据传递链路——数据从 provider(server)出发,经由 bootstrap 完成节点发现与路由,最终被 requester(client)取回并校验字节一致。
三个节点的角色划分如下:
| 节点 | 容器目录 | 监听端口 | 职责 |
|---|---|---|---|
| bootstrap | test/3nodetest/bootstrap | 4011 (TCP) / 4012 (UDP) | 空 bootstrap 列表的引导节点,仅作为对端发现的锚点 |
| server | test/3nodetest/server | 4021 (TCP) / 4022 (UDP) | 启动 daemon、执行ipfs add添加测试文件、把 CID 写入共享卷 |
| client | test/3nodetest/client | 4031 (TCP) / 4032 (UDP) | 从共享卷读取 CID,通过ipfs cat跨节点取回数据并做完整性校验 |
| data | test/3nodetest/data | 无 | 纯数据卷容器,挂载/data,为 server/client 共享测试文件与 CID |
bootstrap 节点的固定 PeerID 为QmNXuBh8HFsWq68Fid8dMbGNQTh7eG6hV9rr1fQyfmfomE(见 bootstrap/config),server 与 client 的启动脚本都通过环境变量拼装出指向该 PeerID 的 multiaddr 并执行ipfs bootstrap add,从而把三个独立 daemon 连接进同一张网络。
二、环境需求与镜像前提
关联文档明确列出了四项前置条件:
- Docker:容器运行时,负责构建与隔离各节点;
- fig:服务编排工具(Docker Compose 的前身),通过
fig.yml描述多容器拓扑; - Go:用于构建生成随机测试数据所需的辅助工具(
make setup会通过make -C ./../../ test/bin/random编译随机数据生成器); - 名为
zaqwsx_ipfs-test-img的 ipfs 镜像:所有节点的Dockerfile都以该镜像为基底(FROM zaqwsx_ipfs-test-img),因此必须先构建或导入一个内含ipfs二进制的基础镜像。
启动测试的三条命令是:
make setup fig build fig up其中make setup完成两件事(见 test/3nodetest/GNUmakefile):一是构建基础镜像docker_ipfs_image(目标名IMAGE_NAME = ipfs-test-latest),二是生成测试数据文件data/filetiny(直接复制Makefile,体积小)与data/filerand(由../bin/random 50000000生成 50 MB 随机字节)。fig build按各子目录的Dockerfile构建四个服务镜像,fig up一次性启动整个拓扑。
三、fig.yml 拓扑编排详解
test/3nodetest/fig.yml 是整个测试的编排核心,四个服务的关键配置如下:
data: build: ./data volumes: - /data command: sleep 1000000 bootstrap: build: ./bootstrap command: daemon --debug --init expose: - "4011" - "4012/udp" environment: GOLOG_LOG_LEVEL: debug server: build: ./server links: - bootstrap volumes_from: - data expose: - "4021" - "4022/udp" environment: GOLOG_LOG_LEVEL: debug client: build: ./client links: - bootstrap volumes_from: - data expose: - "4031" - "4032/udp" environment: GOLOG_LOG_LEVEL: debug要点解读:
- data 容器:声明
VOLUME ["/data"](见 data/Dockerfile),启动命令为sleep 1000000保持存活,仅作为卷的载体; links: - bootstrap:server 与 client 通过链接获得 bootstrap 容器的网络可达信息,fig 会自动注入形如BOOTSTRAP_PORT_4011_TCP_ADDR、BOOTSTRAP_PORT_4011_TCP_PORT的环境变量,这正是 server/run.sh 与 client/run.sh 拼装 bootstrap multiaddr 的依据;volumes_from: - data:server 与 client 共享 data 容器的/data卷,CID 与测试文件经由该卷在两者间传递;GOLOG_LOG_LEVEL: debug:所有节点以 debug 级别输出 Go 日志,便于排查 DHT 发现与块交换细节;command: daemon --debug --init:bootstrap 直接以 daemon 模式启动,--init确保仓库已初始化;server/client 则通过各自Dockerfile的ENTRYPOINT ["/bin/bash"]+CMD [run.sh]执行自定义脚本。
四、自动化执行链路:run-test-on-img.sh
除手动三步外,仓库还提供了全自动执行脚本 test/3nodetest/run-test-on-img.sh,其执行流程为:
- 以参数指定的镜像引用(默认
ipfs-test-latest)在docker images中查找镜像 ID,并docker tag为各 Dockerfile 期望的zaqwsx_ipfs-test-img; - 执行
fig build --no-cache强制重新构建; - 执行
fig up --no-color | tee build/fig.log,把全量输出落入日志; - 依次执行
make save_logs与make save_profiling_data收集调试产物(失败不阻断); - 由于
fig up本身不返回可用的退出码,脚本用tail build/fig.log | grep "exited with code 0"判断测试是否真正成功。
其中IPFS_PROF=true(各 Dockerfile 均设置)会使 daemon 输出 profiling 数据,配合make save_profiling_data(调用 test/3nodetest/bin/save_profiling_data.sh)保存,供性能分析使用。
五、server:提供数据的一侧
server/run.sh 的流程完整展示了“提供者”节点的行为:
ipfs bootstrap add /ip4/$BOOTSTRAP_PORT_4011_TCP_ADDR/tcp/$BOOTSTRAP_PORT_4011_TCP_PORT/p2p/QmNXuBh8HFsWq68Fid8dMbGNQTh7eG6hV9rr1fQyfmfomE ipfs bootstrap # list bootstrap nodes for debugging ipfs daemon --debug & sleep 3 cd /tmp ipfs add -q /data/filetiny > tmptiny mv tmptiny /data/idtiny ipfs add -q /data/filerand > tmprand mv tmprand /data/idrand sleep 10000000关键细节:
- 先
ipfs bootstrap add指向 bootstrap 节点,再启动 daemon,保证节点入网可被发现; ipfs add -q只输出 CID(-q/--quiet),并把 CID 写入共享卷/data/idtiny、/data/idrand——这是 server 与 client 之间的“信令通道”;cd /tmp后再执行 add 命令,是刻意为之:避免 client 侧的命令 profiling 数据覆盖 daemon 自身的 profiling 数据(脚本注释明确说明);- 末尾
sleep 10000000保持容器存活,等待 client 拉取完成。
六、client:取回并校验数据的一侧
client/run.sh 实现了“请求者”节点的完整校验逻辑:
ipfs bootstrap add /ip4/$BOOTSTRAP_PORT_4011_TCP_ADDR/tcp/$BOOTSTRAP_PORT_4011_TCP_PORT/p2p/QmNXuBh8HFsWq68Fid8dMbGNQTh7eG6hV9rr1fQyfmfomE ipfs daemon --debug & sleep 3 cd /tmp while [ ! -f /data/idtiny ] do echo "3nodetest> waiting for server to add the file..." sleep 1 done ipfs cat $(cat /data/idtiny) > filetiny diff -u filetiny /data/filetiny if (($? > 0)); then printf '%s\n' 'files did not match' >&2 exit 1 fi # ...对 filerand 重复同样流程... echo "3nodetest> success"要点:
- 采用轮询而非硬编码 sleep:
while [ ! -f /data/idtiny ]循环等待 server 完成 add 并写入 CID,避免时序竞态; ipfs cat $(cat /data/idtiny)依据 CID 从网络中取回文件,覆盖 DHT 发现 → 连接 provider → Bitswap 取块的完整链路;diff -u与原始测试文件逐字节比对,任一文件不一致即以非零退出码失败;全部一致则输出3nodetest> success,这也是前文 fig.log 中exited with code 0判定成功的数据来源;- 校验先小文件(filetiny)后大文件(filerand,50 MB 随机数据),可同时验证小对象与大对象的传输正确性。
七、节点配置与固定身份
各节点的config文件展示了测试环境的定制要点(见 bootstrap/config 与 client/config):
- 固定 PeerID 与私钥:
Identity.PeerID与Identity.PrivKey预置,server/client 脚本据此构造固定的 bootstrap multiaddr,测试可重复、可预期; - 空 Bootstrap 列表:
"Bootstrap": []——bootstrap 节点本身不依赖任何外部引导节点,形成一个自包含的隔离网络; - 独立 Swarm 端口:
Addresses.Swarm分别绑定 4011/4021/4031 的 TCP 端口,配合EXPOSE 4012/udp等声明,三节点在同一容器网络中互不冲突; - Datastore:
Type: leveldb,路径/root/.ipfs/datastore; - 镜像构建:各 Dockerfile 均执行
RUN ipfs init -b=2048初始化仓库,随后用预置 config 覆盖生成的配置(mv -f),并设置ENV GOLOG_LOG_FMT nocolor便于日志阅读。
bootstrap 子目录的 README.md 也明确说明:这是一个bootstrap list 为空的引导节点,仅监听 4011/4012。
八、与 Go 层集成测试的对应关系
这套 Docker 化测试的场景在 Go 单元集成测试中同样存在:test/integration/three_legged_cat_test.go中的TestThreeLeggedCatTransfer实现了同一“三腿猫”验证,只是改用 libp2p 的 mocknet 而非真实容器:
func TestThreeLeggedCatTransfer(t *testing.T) { conf := testutil.LatencyConfig{...} if err := RunThreeLeggedCat(RandomBytes(1*unit.MB), conf); err != nil { t.Fatal(err) } }RunThreeLeggedCat(见 test/integration/three_legged_cat_test.go)的流程与容器版一一对应:创建bootstrap、adder(对应 server)、catter(对应 client)三个 mock 节点 →adder与catter通过BootstrapConfigWithPeers接入 bootstrap →adderAPI.Unixfs().Add添加数据 → 显式Provide根 CID 到 DHT →catterAPI.Unixfs().Get取回 →bytes.Equal逐字节比对。该文件还包含多个退化场景变体(TestThreeLeggedCatDegenerateSlowBlockstore、...SlowNetwork、...SlowRouting、100MBMacbookCoastToCoast),分别注入块存储延迟、网络延迟、路由延迟,验证极端条件下的数据完整性——这为理解 3nodetest 覆盖的基础能力提供了 Go 层的对照实现。
九、运行与排查建议
- 首次运行务必先
make setup:它同时完成基础镜像构建与测试数据生成,跳过会导致docker build因缺少data/filetiny而失败; fig为 Docker Compose 的前身工具,其fig.yml语法与现代docker-compose.yml基本兼容,可直接将文件重命名后使用docker-compose build/docker-compose up运行(仓库内 test/integration/GNUmakefile 等也保留了相关测试入口);- 排查失败时优先查看
build/fig.log:测试成功与否取决于其中是否出现exited with code 0;各节点均以GOLOG_LOG_LEVEL=debug输出日志,配合make save_logs收集的日志可定位 DHT 发现、连接与 Bitswap 传输环节的问题; - 若需复现单节点行为,可直接进入容器执行
ipfs bootstrap list查看引导配置、ipfs swarm peers查看已连接对端、ipfs bitswap stat观察块交换状态。
【免费下载链接】kuboIPFS implementation in Go: a daemon that stores and serves content-addressed data, with a CLI, HTTP Gateway, and RPC API项目地址: https://gitcode.com/GitHub_Trending/ku/kubo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考