news 2026/9/11 14:06:04

MongoDB 与 Antithesis:网络模糊测试拓扑构建与测试编排实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MongoDB 与 Antithesis:网络模糊测试拓扑构建与测试编排实践指南

MongoDB 与 Antithesis:网络模糊测试拓扑构建与测试编排实践指南

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

导读

本文基于 MongoDB 官方仓库中的 docs/antithesis/README.md 编写,系统讲解如何将 MongoDB 各种集群拓扑(单节点、副本集、分片集群等)打包成 Docker 镜像并上传到 Antithesis 第三方平台,在其网络模糊测试(network fuzzing)环境中运行测试套件并自动生成缺陷报告。读完本文,你将掌握 Antithesis 基础镜像体系(mongo-binariesworkload)、拓扑镜像与docker-compose.yml的编写规范、初始化脚本的存活要求、如何在 Evergreen 中创建新拓扑任务,以及 Normal resmoke testing 与 Test Composer 两种测试模式的配置方式,并辅以仓库源码(docker_cluster_image_builder.py、antithesis_image_build_and_push.sh)作为实现级佐证。

Antithesis 是什么:第三方网络模糊测试环境

Antithesis 是一家第三方供应商,它提供一个可以进行网络模糊测试的环境。MongoDB 团队将包含docker-compose.yml文件的镜像上传到 Antithesis Docker 仓库,这些docker-compose.yml描述了各种 MongoDB 拓扑(例如分片集群、副本集)。Antithesis 会在自己的环境中对镜像执行docker-compose up,从而拉起对应的多容器应用并运行测试套件。

关键流程如下:

  1. 构建镜像:把描述拓扑的文件(docker-compose.yml、初始化脚本、日志目录等)打包为"拓扑镜像",上传到 Antithesis Docker registry;
  2. 启动拓扑:Antithesis 基于该镜像执行docker-compose up,在真实多容器环境中启动 MongoDB 拓扑;
  3. 注入故障:在测试套件运行期间,Antithesis 会对拓扑执行网络模糊测试(故障注入);
  4. 生成报告:测试结束后,Antithesis 生成一份缺陷报告,标识出被发现的 bug。

整个流程在 CI(Evergreen)侧由 evergreen/antithesis_image_build_and_push.sh 承载:它负责登录 Antithesis 仓库、调用 resmoke 构建三类镜像、在本地做一次 sanity check,然后推送镜像,并在 patch 场景下通过 Antithesis API 触发测试任务。

基础镜像:构建 MongoDB 测试拓扑的积木

base_images目录(仓库中位于 buildscripts/antithesis/base_images/)包含了创建 MongoDB 测试拓扑的"积木",这些镜像会在 Evergreen 的 nightly 构建中通过antithesis image build and push任务上传到 Antithesis Docker registry。目录下有两个子镜像:mongo_binariesworkload

mongo_binaries:系统被测(SUT)镜像

该镜像包含最新的mongomongosmongod二进制,可以用来启动mongod实例、mongos实例或执行mongo命令。它是构建"被测系统(System Under Test)"拓扑的核心积木。

从 mongo_binaries/Dockerfile 可以看到它的关键细节:

  • 基础镜像为ubuntu:22.04
  • EXPOSE 20000-20100:因为 resmoke 从 20000 开始为每个 mongo{d,s} 进程递增分配端口;
  • 安装curlpython3llvm-12libc6-dbggdb等调试与运行依赖(通过 retry_apt.sh 进行最多 6 次指数退避重试,以应对镜像同步期间的 apt 抖动);
  • 复制tsan.suppressions(来自 etc/tsan.suppressions);
  • 通过构建参数注入ASAN_OPTIONSUBSAN_OPTIONSTSAN_OPTIONS,并自动追加external_symbolizer_path(指向 LLVM symbolizer)以及 TSAN 的 suppressions 路径;
  • bin/*复制到/usr/bin/lib/*复制到/usr/lib/,并将libvoidstar.so安装到/usr/lib/libvoidstar.so——libvoidstar.so是 Antithesis 的插桩库,二进制必须链接到它才能被 Antithesis 观测(CI 构建时会用ldd校验这一点,见 docker_cluster_image_builder.py 的_fetch_mongodb_binaries);
  • 将 MongoDB 源码复制到/mongo,最后运行/usr/bin/mongo --version验证安装。

本地开发构建时,由于开发者一般没有真正的libvoidstar.so,构建器会写入一个stub 文件占位(见 docker_cluster_image_builder.py 的_add_libvoidstar_to_build_context);而在 Evergreen 中则必须使用系统真实的/usr/lib/libvoidstar.so并断言其存在。

workload:测试执行容器

workload镜像包含最新的mongo二进制以及resmoke测试运行器。workload 容器不属于实际拓扑的一部分,它的职责是:

  • 执行mongo命令完成拓扑的初始化设置;
  • 在已有拓扑上运行测试套件,例如:
buildscripts/resmoke.py run --suite antithesis_concurrency_sharded_with_stepdowns_and_balancer

每个拓扑必须恰好有 1 个 workload 容器。

注意:在workload镜像构建期间,evergreen/antithesis_image_build_and_push.sh 运行后会生成"antithesis 兼容"的测试套件,并以antithesis_前缀命名。这些套件才是可以在 Antithesis 中运行的套件,它们从workload容器内部可用。

从 workload/Dockerfile 可以看到它与 mongo_binaries 镜像的区别:

  • 额外安装gitsoftware-properties-common,并通过 deadsnakes PPA 安装Python 3.13(resmoke 项目要求 >= 3.13),把python3.13软链为系统python/python3
  • 复制 QA 仓库到/QA(并软链为/mongo/jstests/qa_tests)、jstestfuzz 仓库到/jstestfuzz(软链到/mongo/jstestfuzz);
  • 使用uv(版本由 buildscripts/uv_version.txt 锁定)在/opt/venv中同步 MongoDB Python 依赖;
  • 软链 enterprise 模块到/mongo/jstests/enterprise_tests

镜像的获取与构建逻辑

无论是mongo_binaries还是workload,其构建都统一由DockerComposeImageBuilder驱动(见 docker_cluster_image_builder.py):

  • 在 Evergreen 中:master分支的二进制由编译任务产出,还需用db-contrib-tool setup-repro-env拉取last-continuouslast-lts二进制;
  • 本地开发:要求安装db-contrib-toolpip install db-contrib-toolpipx install db-contrib-tool),用它下载 Ubuntu 22.04 的 MongoDB 二进制;
  • workload 镜像要求存在mongo_enterprise_modules仓库(src/mongo/db/modules/enterprise);
  • 在 Evergreen 中构建时,依赖evergreen/antithesis_clone_repos.sh预先克隆 QA、jstestfuzz 等仓库,因为 GitHub token 会在构建前提前生成并在一小时后过期,不能在构建过程中再执行克隆。

拓扑镜像:FROM scratch 的文件系统容器

"拓扑镜像"(对应base_images中的Dockerfile一节所描述的角色)把启动对应拓扑所需的全部文件组装成一个镜像:一个docker-compose.yml、一个logs目录、一个scripts目录和一个data目录。只要结构正确,你就能从该镜像复制出这些文件与目录,然后本地执行docker-compose up复现同样的拓扑。

该类镜像在构建时由 docker_cluster_image_builder.py 的_add_docker_compose_configuration_to_build_context动态生成,生成出的 Dockerfile 与文档中给出的示例一致:

FROM scratch COPY docker-compose.yml / ADD --chmod=0755 scripts /scripts ADD logs /logs ADD data /data ADD debug /debug

(若配置了 Test Composer 目录,还会额外ADD --chmod=0755 test_composer /test_composer。)

为什么用FROM scratch这些镜像仅仅作为存放拓扑所需全部文件的文件系统载体,不运行任何程序,因此使用FROM scratch最小化体积。镜像的实际运行者是被docker-compose.yml引用的mongo-binariesworkload镜像。所有拓扑镜像都在antithesis image build and push任务期间构建并上传到 Antithesis Docker registry;其中/data/logs等目录由 evergreen/antithesis_image_build_and_push.sh 脚本创建。

docker-compose.yml:拓扑描述与故障注入控制

docker-compose.yml描述了如何利用mongo-binariesworkload镜像构造目标拓扑。以下是文档中给出的分片集群示例(与构建器生成的结构一致,见 docker_cluster_image_builder.py 中create_docker_compose_service的字段映射):

version: '3.0' services: configsvr1: container_name: configsvr1 hostname: configsvr1 image: mongo-binaries:evergreen-latest-master volumes: - ./logs/configsvr1:/var/log/mongodb/ - ./scripts:/scripts/ - ./data/configsvr1:/data/configdb/ command: /bin/bash /scripts/configsvr_init.sh networks: antithesis-net: ipv4_address: 10.20.20.6 # Set the an IPv4 with an address of 10.20.20.130 or higher # to be ignored by the fault injector # configsvr2: ... configsvr3: ... database1: ... container_name: database1 hostname: database1 image: mongo-binaries:evergreen-latest-master volumes: - ./logs/database1:/var/log/mongodb/ - ./scripts:/scripts/ - ./data/database1:/data/db/ command: /bin/bash /scripts/database_init.sh Shard1 networks: antithesis-net: ipv4_address: 10.20.20.3 # Set the an IPv4 with an address of 10.20.20.130 or higher # to be ignored by the fault injector # database2: ... database3: ... database4: ... database5: ... database6: ... mongos: container_name: mongos hostname: mongos image: mongo-binaries:evergreen-latest-master volumes: - ./logs/mongos:/var/log/mongodb/ - ./scripts:/scripts/ command: python3 /scripts/mongos_init.py depends_on: - "database1" - "database2" - "database3" - "database4" - "database5" - "database6" - "configsvr1" - "configsvr2" - "configsvr3" networks: antithesis-net: ipv4_address: 10.20.20.9 # The subnet provided here is an example # An alternative subnet can be used workload: container_name: workload hostname: workload image: workload:evergreen-latest-master volumes: - ./logs/workload:/var/log/resmoke/ - ./scripts:/scripts/ command: python3 /scripts/workload_init.py depends_on: - "mongos" networks: antithesis-net: ipv4_address: 10.20.20.130 # The subnet provided here is an example # An alternative subnet can be used networks: antithesis-net: driver: bridge ipam: config: - subnet: 10.20.20.0/24

编写规范与约束

  1. 每个容器必须有commandcommand运行一个初始化脚本,脚本必须放在以 volume 挂载的scripts目录中。写法必须是/bin/bash /scripts/[script_name].shpython3 /scripts/[script_name].py。这是拓扑在 Antithesis 中正常启动的硬性要求。
  2. 日志路由:创建mongodmongos实例时,使用--logpath /var/log/mongodb/mongodb.log并把./logs/<容器名>挂载到/var/log/mongodb/(如示例中database1的做法)。这样一旦 Antithesis 检测到 bug,可以方便地取回日志。
  3. IPv4 地址与故障注入豁免ipv4_address设置为10.20.20.130 或更高的容器不会被网络模糊测试影响。例如workload容器通常不希望被网络模糊测试干扰,因此示例中分配了10.20.20.130。构建器源码中与此对应:next_available_fault_enabled_ip从 2 开始递增(受故障注入),next_available_fault_disabled_ip从 130 开始递增(不受故障注入)。
  4. 镜像 tag:所有镜像统一使用evergreen-latest-mastertag(patch 场景则为evergreen-patch或自定义 tag),必要时由 evergreen/antithesis_image_build_and_push.sh 自动更新。
  5. 额外的 ulimits:构建器还会为每个服务加上ulimits.memlock = -1。这是因为 s2n-tls(handoff 传输层使用)在启动时会调用mlock(),而 Antithesis 容器默认的RLIMIT_MEMLOCK很低,会导致s2n_config_new_minimal()失败、中止传输层初始化,放开 memlock 限制后 mongo{d,s} 才能正常启动。

scripts:初始化脚本的写法与存活要求

初始化脚本用于在容器启动时完成拓扑搭建。文档以sharded_cluster拓扑为例介绍了两种写法:利用utils.py中的工具方法编写 Python 脚本(如mongos_init.py),或使用简单的 shell 脚本(如database_init.py)。

当前仓库中,初始化脚本由 docker_cluster_image_builder.py 自动生成:

  • 每个 mongo{d,s} 进程对应一个scripts/<服务名>.sh,内容就是该进程的完整启动参数(process.argsshlex.quote拼接);
  • scripts/workload.sh固定为tail -f /dev/null,保持 workload 容器存活;
  • 同时生成scripts/run_resmoke.sh(封装 resmoke 运行命令)和scripts/print_connection_string.sh(打印 resmoke fixture 的 shell 连接串,Test Composer 脚本依赖它获取连接 URL)。

核心约束:初始化脚本不能结束,否则底层容器会退出。保持容器存活的方式有两种:

  • Python 脚本:使用无限 while 循环;
  • Shell 脚本:使用tail -f /dev/null

如何创建一个新的 Antithesis 测试拓扑

创建新拓扑需要谨慎,以确保高效利用有限的测试资源。步骤是:创建一个继承antithesis_task_template、并打上antithesistag 的新 Evergreen 任务,把指定的suite传给antithesis image build and push任务。可以参考现有的其他示例来起步。

完整的模板式任务配置示例(来自 buildscripts/antithesis/test_composer/README.md):

- <<: *antithesis_task_template name: antithesis_my_task commands: - func: "antithesis image build and push" vars: suite: concurrency_sharded_replication_with_balancer_and_config_transitions_and_add_remove_shard resmoke_args: >- --runAllFeatureFlagTests antithesis_test_composer_dir: basic_js_commands

antithesis image build and push任务内部的核心命令(见 antithesis_image_build_and_push.sh):

buildscripts/resmoke.py run --suite ${suite} ${resmoke_args} \ --dockerComposeTag $tag \ --dockerComposeBuildImages workload,config,mongo-binaries \ --dockerComposeBuildEnv evergreen ${extra_args}

构建完成后会执行 sanity check:docker-compose up -d拉起拓扑,在 workload 容器内以--sanityCheck --externalSUT运行一次 resmoke(带 1 小时超时),收集日志后再把镜像推送到 Antithesis 仓库。其中mongo-binariesworkload两个共享镜像通过 S3 锁(buildscripts/s3_lock.py)保证并发推送互斥。

如何在 Antithesis 中测试你的套件

在 Evergreen patch 中传入参数schedule_antithesis_tests

evergreen patch --param schedule_antithesis_tests=true

当 Evergreen patch 中构建出 antithesis 镜像后,系统会向 Antithesis 发送一个 API 请求,让 Antithesis 运行你新建的镜像一小时。运行结束后,报告会通过邮件发送给你。

重要提示:这个参数会作用于你在 patch 中安排的每一个 antithesis 任务。一次 patch 中不要同时安排超过 1~2 个携带该参数的任务,否则会耗尽分配给项目的 Antithesis 测试额度。

从源码看,antithesis_image_build_and_push.sh 在 patch 且schedule_antithesis_tests=true时,会用jq组装参数(antithesis.config_imageantithesis.imagescustom.duration设为.5小时、antithesis.report.recipients设为作者邮箱、antithesis.is_ephemeral设为true),然后调用curl -X POST请求 Antithesis 的 launch API 端点触发测试。

Antithesis 中的两种测试模式

Normal resmoke testing(默认模式)

Antithesis 会持续运行你的 resmoke 套件,每次从中随机取一个测试来执行。大多数使用 Python fixture 的 resmoke 套件都开箱即用地支持这种模式,其运行方式与 Evergreen 中的测试非常相似。如果任务上没有指定antithesis_test_composer_dir变量,Evergreen 中的 antithesis 任务默认就是这种模式。

Test Composer(模板驱动的自主测试)

Antithesis 提供了名为 Test Composer 的能力,用于针对集群运行"测试模板"。Test Composer 通过让你定义模板,引导 Antithesis 在多种系统状态下自主生成数千个测试用例,实现自主化测试。只要任务上指定了antithesis_test_composer_dir变量,Evergreen 任务就会自动使用 Test Composer。

Test Composer 采用一套命名约定(parallel_driver_*singleton_driver_*serial_driver_*first_*eventually_*finally_*anytime_*)来告诉 Antithesis 何时以及如何运行脚本,从而控制并行度、故障注入与命令顺序。仓库中内置了两个模板:

  • basic_js_commands:针对单个mongod的并行 JavaScript 负载(find/insert/update/delete/aggregate/事务/dbCheck 等),共享 js/commands.js 中的重试逻辑(处理瞬时网络错误、server selection 失败与可重试写错误);
  • random_resmoke:以随机种子(--seed $(od -vAn -N4 -tu4 < /dev/urandom))加--shuffle --sanityCheck的方式运行现有 resmoke jstests。

关于命名规范、现有模板、最佳实践、本地开发方法以及 Evergreen 配置细节,请参阅 buildscripts/antithesis/test_composer/README.md。

附加资源

如果希望进一步利用 Antithesis,可以参考仓库内以下资源继续深入:

  • 构建与推送全流程:evergreen/antithesis_image_build_and_push.sh
  • 拓扑镜像与 docker-compose 的生成实现:buildscripts/resmokelib/testing/docker_cluster_image_builder.py
  • 基础镜像定义:buildscripts/antithesis/base_images/mongo_binaries/Dockerfile 与 buildscripts/antithesis/base_images/workload/Dockerfile
  • Test Composer 模板与指南:buildscripts/antithesis/test_composer/README.md
  • 测试钩子中的 Antithesis 日志支持:buildscripts/resmokelib/testing/hooks/README.md

【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 14:04:28

软考中级考试科目全解析与备考指南

1. 软考中级考试概述计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;是我国IT行业最具权威性的专业技术资格认证之一。作为行业内的"硬通货"&#xff0c;软考证书不仅是专业能力的证明&#xff0c;更是职称评定、积分…

作者头像 李华
网站建设 2026/9/11 14:03:26

SPI通信协议详解:从基础原理到实战优化

1. SPI通信的本质&#xff1a;同步串行的主从对话 SPI&#xff08;Serial Peripheral Interface&#xff09;本质上是一种全双工、同步串行通信协议。我第一次接触SPI是在调试一个温湿度传感器时&#xff0c;当时被它简洁的四线制结构所吸引。与UART需要精确匹配波特率不同&…

作者头像 李华
网站建设 2026/9/11 14:03:04

嵌入式KWS静态审计:ARM Cortex-M上TinyML落地的工程可靠性保障

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 14:01:31

PCSX2 PS2模拟器:把老主机塞进电脑,经典游戏跑出4K画质

PCSX2 PS2模拟器&#xff1a;把老主机塞进电脑&#xff0c;经典游戏跑出4K画质 【免费下载链接】pcsx2 PCSX2 - The Playstation 2 Emulator 项目地址: https://gitcode.com/GitHub_Trending/pc/pcsx2 PCSX2是一款免费开源的PS2模拟器&#xff0c;由开发团队维护了20多年…

作者头像 李华
网站建设 2026/9/11 14:00:39

Windows远程线程DLL注入技术详解与实践

1. 远程线程DLL注入技术解析远程线程DLL注入是Windows系统下一种经典的进程间通信与代码执行技术。简单来说&#xff0c;它允许我们将一个动态链接库&#xff08;DLL&#xff09;加载到目标进程的地址空间中&#xff0c;并在该进程内创建新线程执行我们的代码。这项技术在软件调…

作者头像 李华