ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

youki e2e 测试体系全指南:从 Rust OCI 集成测试到 Kind 多节点集群验证

youki e2e 测试体系全指南:从 Rust OCI 集成测试到 Kind 多节点集群验证 容器运行时云原生【免费下载链接】youkiA container runtime written in Rust项目地址https://gitcode.com/gh_mirrors/yo/youki点击查看免费下载本篇技术指南以 e2e 测试总览文档 为骨架系统梳理 youkiRust 编写的 OCI 容器运行时的四层端到端测试体系Rust OCI 集成测试contest runtimetest test_framework、containerd 集成测试、OCI runtime-tools 符合性测试、以及基于 Kind 的 Kubernetes 运行时验证。读完本文你将掌握每个测试的用途、一键运行命令基于 justfile、如何编写并注册一个新的集成测试用例以及如何把 youki 部署进单节点与多节点 Kind 集群做冒烟验证。测试全景youki 的四类 e2e 测试youki 的 e2e端到端测试不是单一脚本而是覆盖从底层运行时行为到上层编排系统集成四个不同层次的测试集合由 e2e_tests.md 统一索引测试类别验证目标核心入口rust oci testsyouki 作为底层容器运行时的原始集成测试OCI 运行时生命周期行为just test-contestcontainerd integration testcontainerd 的集成测试套件以 youki 作为运行时运行just containerd-testruntime toolsOCI 官方管理的 runtime-tools 符合性测试验证满足 OCI Runtime Specjust test-ociKubernetes test通过 Kind 验证 youki 作为 Kubernetes 容器运行时正常工作just test-kind/just test-kind-deploy这四层测试的关系可以这样理解rust oci tests 与 runtime tools 验证的是OCI 运行时契约本身containerd 测试验证的是上层容器引擎 运行时的衔接而 Kind 测试验证的是Kubernetes 运行时在生产形态下的工作状态。它们共同构成 youki 从开发到上线前的质量防线。第一层Rust OCI 集成测试contest定位与设计动机rust_oci_test.md 明确指出这套测试是youki 自有的、用于验证底层容器运行时行为的原始集成测试。它的诞生源于一个实际痛点OCI 官方 runtime-tools 的验证测试用 Go 编写且其输出解析还依赖 Node.js这意味着 youki 开发者被迫维护 Go 与 Node 两个额外的语言环境。因此 youki 将这些测试移植为 Rust 实现形成一个可以随代码变更随时本地运行的测试集详见 integration_test.md。从仓库结构看这套测试由三个相互协作的 crate 组成位于 tests/contest 目录contest测试主程序负责构造 OCI Runtime Spec、驱动容器生命周期create/start/exec/kill/delete 等、汇总测试结果runtimetest一个静态链接的小二进制被放入容器内执行从容器内部验证约束readonly paths、seccomp、capabilities、cgroup 等是否真正生效test_framework通用测试框架 crate提供Test、TestGroup、TestManager、TestResult等结构与 traitcontest 基于它组织测试。运行方式just test-contest该命令展开后的实际动作见 justfilesudo scripts/contest.sh ./youkicontest.sh 脚本会依次完成确认运行时二进制存在、按 CPU 架构选择测试 bundle优先bundle-$(uname -m).tar.gz缺失时回退到 x86_64 的bundle.tar.gz、调用contest run --runtime runtime --runtimetest ./runtimetest运行全部测试最后通过扫描日志中not ok的出现次数判定整体成败。得益于test-contest任务的可选参数justfile 中的*TESTNAME你可以只运行选中的测试组例如just test-contest lifecycle::create,delete cgroups::memory其测试选择格式在 contest/src/main.rs 中定义-t group1::test1,test3 group2 group3::test5即组名后跟::和逗号分隔的用例名不带::则运行整个测试组。contest 二进制还提供list子命令just contest-list列出全部已注册测试组。另外仓库提供validate-contest-runc任务justfile以 runc 为被测运行时跑同一套测试用于在 CI 中验证测试本身的正确性——因为 contest 也处于持续开发中。框架基石test_framework 的抽象要理解如何编写测试先看框架提供的最小抽象testable.rsTestResult枚举三种结果——Passed通过、Skipped(String)跳过并给出原因如当前环境不满足前置条件、Failed(Error)失败。它是扩展版 ResultOk变体不带值Testabletrait要求实现get_name()与run() - TestResultcan_run()有默认实现默认 true用于条件测试TestableGrouptrait要求实现get_name()、parallel()、run_all()、run_selected()test_result!宏把ResultT快速转换为TestResultErr 时直接return TestResult::Failed(err)配合FromResultT实现使用。并行执行是默认行为TestGrouptest_group.rs默认parallel: true组内测试通过 crossbeam 线程池并发运行TestManagertest_manager.rs则按 CPU 核数分批并发执行各测试组并用thread::scope保证线程安全。如果你的测试有先后依赖例如容器生命周期必须先 create 再 start 再 stop需要调用set_nonparallel()标记串行或自行实现 trait 以精确控制执行顺序——这也是 test_framework.md 强调的场景。完整示例编写一个 hello world 测试下面按 rust_oci_test.md 给出的五个步骤对照仓库中的真实样例 hello_world.rs 逐步讲解。第 1 步构建要验证的 OCI Runtime Spec测试框架会自动把 runtimetest 放入容器因此常规做法是让 Spec 的进程参数指向runtimetest 测试名fn create_spec() - ResultSpec { SpecBuilder::default() .process( ProcessBuilder::default() .args( [runtimetest, hello_world] .iter() .map(|s| s.to_string()) .collect::VecString(), ) .build()?, ) .build() .context(failed to create spec) }进程参数[runtimetest, hello_world]中的第二个元素就是 runtimetest 主程序中分发的测试名见下文第 5 步。第 2 步准备返回TestResult的测试函数fn example_test() - TestResult { let spec test_result!(create_spec()); test_inside_container(spec, CreateOptions::default(), |_| Ok(())) }test_inside_container是 test_utils.rs 提供的核心工具函数它按 Spec 创建并启动容器等待容器内进程结束然后检查其 stderr 是否为空——非空即判定失败。这正是从容器内部验证约束的实现机制。关于create_container与 stdio 管道还有一个容易踩的坑integration_test.md 有专门说明youki create进程 fork 出的子进程会一直等待start信号才 exec 容器程序因此如果只是创建容器而没有启动它对返回的Child调用wait_with_output()会永久挂起正确的做法是在调用start之后、容器真正运行起来时再收集 stdout/stderr。第 3 步创建TestGroup并注册用例pub fn get_example_test() - TestGroup { let mut test_group TestGroup::new(example); let test1 Test::new(hello world, Box::new(example_test)); test_group.add(vec![Box::new(test1)]); test_group }TestGroup::new(example)定义了组名Test::new(hello world, ...)定义用例名二者构成example::hello world的完整定位标识。第 4 步把TestGroup注册进TestManager在 contest/src/main.rs 中let mut tm TestManager::new(); let example get_example_test(); tm.add_test_group(Box::new(example));TestManager内部用BTreeMap以组名维护全部测试组还可通过add_cleanup注册清理回调contest 注册了cgroups::cleanup_v2用于测试结束后清理 cgroup v2 残留。第 5 步编写容器内的验证逻辑在 runtimetest 主程序 main.rs 中注册测试名分发fn main() { let spec get_spec(); let args: VecString env::args().collect(); let execute_test match args.get(1) { Some(execute_test) execute_test.to_string(), None return eprintln!(error due to execute test name not found), }; match *execute_test { hello_world tests::hello_world(spec), // ... 其余测试名分发 _ eprintln!(error due to unexpected execute test name: {execute_test}), } }runtimetest 从容器内的固定路径/config.json加载 Specconst SPEC_PATH: str /config.json然后在 tests.rs 中实现实际校验pub fn hello_world(_spec: Spec) { println!(Hello world); }验证函数通过println!输出正常信息、通过eprintln!输出错误test_inside_container侧正是依赖stderr 为空来判定测试通过。runtimetest必须静态链接的原因runtimetest 之所以独立于主 workspaceruntimetest.md有两个原因必须静态链接 crt0如果动态链接二进制会依赖/lib64/ld-linux-x86-64.so.2解释器而容器内通常没有/lib64目录二进制将无法运行。可以用以下命令检查readelf -l path/to/binary | grep program interpreter输出[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]表示动态链接无输出则为静态链接。file命令同样可以判断输出含statically linked即可在容器内运行。避免双重编译开销runtimetest 依赖oci-spec、nix等包这些也是主 workspace 其他 crate 的依赖。若放入同一 workspace这些依赖需分别按动态供主工程与静态供 runtimetest编译两次拖慢开发迭代。独立成 crate 后拥有独立target/目录改动哪个就只重编哪个。既有测试覆盖面contest 的测试覆盖相当广contest/src/main.rs 中注册了 50 个测试组包括但不限于cgroups v2 的 cpu/memory/pids、seccomp 与 seccomp notify、容器生命周期create/start/stop/delete/exec/kill、hooksprestart/poststart/poststop 及失败场景、readonly/masked paths、mount propagation 与递归挂载、hostname/domainname/sysctl、进程 capabilities 及其边界情况、rlimits、oom score adj、uid mappings、网络设备、terminal、checkpoint/restore、scheduler 策略、io priority、memory policyNUMA等。runtimetest 侧则通过/proc、netlink、sched_getattr、ioprio_get等系统接口做进程内自证。第二层containerd 集成测试containerd_integration_test_using_youki.md 说明该测试的作用是让 containerd 官方集成测试套件以 youki 作为运行时来执行从而验证 containerd 与 youki 的衔接。本地运行方式依赖 Vagrant见 justfilejust containerd-test展开后是vagrant up containerd2youki加vagrant provision containerd2youki --provision-with test即拉起一台预置了 containerd 与 youki 的虚拟机并执行测试。清理环境使用just clean-containerd-testvagrant destroy containerd2youki。注意该测试的一键运行是以 Vagrant 虚拟机为前提的与本机直接跑just test-contest不同需要相应的基础设施准备。第三层OCI runtime-tools 符合性测试runtime_tools.md 说明这类测试使用OCI 官方维护的 runtime-tools作为检验运行时是否满足 OCI Runtime Spec 的测试工具。本地运行需要先初始化子模块仓库以 git submodule 形式引用了 runtime-tools 源码见 tests/oci-runtime-tests$ git submodule update --init --recursive $ just test-ocitest-oci在 justfile 中展开为scripts/oci_integration_tests.sh由脚本驱动 runtime-tools 的验证流程。另外 justfile 中test-integration: test-oci test-contest把两层测试合并为一次集成测试入口而test-all则在不包含 rust-oci 的情况下聚合基础单测、特性编译测试与 containerd 测试说明 contest 套件整体耗时较长故从默认全量门禁中分离。第四层Kubernetes 测试Kindkubernetes_test.md 说明该测试通过KindKubernetes in Docker验证 youki 作为 Kubernetes 容器运行时是否工作正常。仓库提供了单节点与多节点两种形态。单节点部署测试流程构建内置 youki 的自定义 Kind 节点镜像 → 创建集群 → 用 RuntimeClass 指定 youki 为运行时 → 部署 nginx Pod 冒烟验证。$ just test-kind清理已有集群$ just clean-test-kind其实现细节justfile先用docker buildx基于 tests/k8s/Dockerfile 构建 kind 节点镜像并加载进 docker再kind create cluster创建名为youki的集群随后kubectl applyruntimeclass.yaml 与 deploy.yaml等待nginx-deployment可用后kubectl get pods -o wide查看运行结果最后删除资源。RuntimeClass 声明handler: youkiDeployment 的 Pod 模板通过runtimeClassName: youki指定使用 youki。justfile 中还提供了 systemd cgroup 变体test-kind-systemd-cgroup针对 dbus socket 路径的回归测试及对应清理命令。多节点部署测试多节点变体更贴近生产集群的安装方式kubernetes_test.md集群节点保持 vanilla 的kindest/node镜像通过在每个节点上运行的 DaemonSet 把 youki 安装到宿主机并在运行时注册进 containerd。$ just test-kind-deploy若只想拉起集群与 DaemonSet、跳过 nginx 冒烟测试$ just kind-deploy清理$ just clean-test-kind-deploy实现细节justfilekind-cluster-multi按 kind-config.yaml 创建 1 个 control-plane 2 个 worker 的三节点集群youki-installer-image构建youki-installer:latest镜像kind-deploy把镜像加载进集群并应用 youki-deploy.yaml等待ds/youki-deploy完成 rollouttest-kind-deploy随后部署 nginx Deployment 并等待可用。这套流程同时演示了 youki 在 Kubernetes 环境的两种接入模式自定义节点镜像内置单节点与DaemonSet 动态安装多节点。常见问题与排查要点contest 需要 root 权限test-contest会以sudo执行 contest.sh因为容器创建涉及 cgroup、namespace、挂载等特权操作runtimetest 无法在容器内运行优先检查是否静态链接file或readelf -l判断这是文档明确强调的坑测试 hang 住注意create_container返回的 Child 在 start 之前不能wait_with_output()否则会因等待 start 信号而永久阻塞选中测试语法-t参数支持组名::用例1,用例2与单独组名两种粒度可通过just contest-list查看全部注册组名bundle 架构回退contest.sh 优先使用当前架构的 bundle如bundle-aarch64.tar.gz缺失时回退默认 x86_64 bundle跨架构运行时需留意。结语youki 的 e2e 测试体系按运行时契约 → 容器引擎衔接 → Kubernetes 生产形态三层递进覆盖从 contest 的 Rust 原生集成测试配合静态链接的 runtimetest 与可复用的 test_framework、containerd 测试的 Vagrant 流程、OCI runtime-tools 符合性验证到 Kind 单/多节点测试 的完整链路。对运行时开发者而言just test-contest与 contest 的Spec 构造 容器内自证模式是日常迭代中最常使用的工具对平台工程师而言test-kind-deploy则演示了把 youki 引入 Kubernetes 集群的真实安装路径。所有一键命令均可在仓库根目录的 justfile 中追溯其底层实现。赞分享容器运行时云原生【免费下载链接】youkiA container runtime written in Rust项目地址https://gitcode.com/gh_mirrors/yo/youki点击查看免费下载相关推荐youki 的 Kubernetes 集成测试指南基于 Kind 的单节点与多节点部署验证youki 的 Kubernetes 集成测试指南基于 Kind 的单节点与多节点部署验证 导读 本文讲解 youki 容器运行时用 Rust 编写的 OC容器运行时云原生youki 集成测试框架 test_framework 完全指南从 Testable 到 TestManager 的并行测试体系youki 集成测试框架 test_framework 完全指南从 Testable 到 TestManager 的并行测试体系 本文以 tests/cont容器运行时云原生Opik Python SDK 测试实战指南从 fake_backend 集成测试到 E2E 验证器Opik Python SDK 测试实战指南从 fake_backend 集成测试到 E2E 验证器 本文是 Opikcomet llm 仓库Python人工智能LLMOps模型评测可观测性AI AgentAI 应用后端前端上一篇WingetUI国际化实践从语言文件到文化适配的全流程下一篇用 ship 命令统一 Git 工作流从分支创建到 Pull Request 提交的完整实践openstatus 仓库示例创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表