Agent Skills
› zeabur-oss/zeabur
› zeabur-oss-cluster-tests
zeabur-oss-cluster-tests
GitHub提供 Zeabur OSS 项目 Kubernetes 集成与端到端测试的环境配置、运行流程及编写规范。涵盖临时集群搭建、VM 快照管理、Rust 测试执行命令,以及基于 RBAC 边界和真实 API 服务器的断言最佳实践,用于调试或运行集群测试。
Trigger Scenarios
需要运行或编写 Kubernetes 集成测试
集群测试失败需排查环境或逻辑问题
需要了解 disposable cluster 的构建与管理方式
Install
npx skills add zeabur-oss/zeabur --skill zeabur-oss-cluster-tests -g -y
SKILL.md
Frontmatter
{
"name": "zeabur-oss-cluster-tests",
"description": "Where and how any zeabur-oss repository runs its Kubernetes integration and end-to-end tests (a disposable k3d, k3s or kind cluster on a Linux machine or VM, its own kubeconfig, a VM snapshot restored after every run), and how to write and debug a cluster test. Use before running or writing a test that needs a cluster or Docker, or when one fails."
}
Zeabur OSS cluster tests
The repository's cluster-test skill (or its CONTRIBUTING.md) has the cluster script, the test
commands, its profiles and its known failures. These rules hold in every repository.
Where they run
- A disposable cluster where you are cluster admin, with its own kubeconfig
(
export KUBECONFIG=<the script's kubeconfig>), never your normal context or one you did not create. - On a Linux machine or VM with Docker and Nix, not on a workstation you care about: the
tests create clusters, images and volumes. Sync the working tree there and run every command
inside
nix developon that machine:rsync -a --delete --exclude target --exclude node_modules ./ host:<repo>/(exclude the repository's other build output too). - On a VM, snapshot its clean state and restore it after every run. The tests run in the VM's
own environment, not a fresh container: what one run leaves (clusters, images, volumes, build
output,
node_modules, tools installed by hand) can make the next pass where a fresh GitHub runner fails. Take the snapshot once Nix and Docker are installed (after onenix develop, so the store is warm, if you like), and restore it before the next run (virsh snapshot-revert,prlctl snapshot-switch, or your hypervisor's equivalent). - One run at a time per machine: check
pgrep -af 'ci-local.sh|ci.sh'first. - A pull request's GitHub checks remain the answer. To run a cluster job as CI does, run
scripts/ci.sh <job>on that machine (zeabur-oss-ci). - Clean up with the repository's
downorcluster deletecommand when you are done.
Rust cluster tests
Cluster tests are #[ignore]d and live in each crate's tests/kubernetes.rs:
cargo nextest run --locked --run-ignored only -E 'binary(kubernetes)'
Writing one
- Assert through a person. The admin context only prepares a fresh namespace, a service account standing in for a person, its Role and RoleBinding, and a token from the TokenRequest API. Every assertion goes through that person's credential, never through the admin client. Clean up the namespace and cluster-scoped objects even when the test fails.
- Test the boundary, not only the happy path: a namespace outside the person's rights is
403; deleting their RoleBinding makes the very next request403; another field manager's field is a409without force. - A fake API server shows our logic. What only kube-apiserver decides (RBAC, server-side
apply,
resourceVersionconflicts, admission, schema validation) needs a test against a real one. - Wait, do not sleep. Something that changes on its own (a pod, a watch, a poll every few seconds) is polled with a deadline for what must eventually hold, and the assertion accepts every state the system may legitimately be in.
What to check when something fails
403where you expected success:kubectl auth can-i --as system:serviceaccount:<ns>:<sa> <verb> <resource> -n <ns>. WebSocket exec needscreateonpods/exec, not onlyget.- A pod never starts:
kubectl describe pod <pod> -n <ns>; the image was not imported or pulled.k3d image importcan printctr"content digest … not found" and still exit 0 for a multi-platform image whose other platforms are absent; read its output and the pod's events. cannot change roleRef: a ClusterRoleBinding from an older install has a different role; delete it and apply again.- NodePort refused: kube-proxy needs a moment after a Service is created; poll.
- Concurrent deletes on k3s can return 500 for the loser; code fails closed, tests accept it.
- Memory: measure it with the kubelet summary API
(
/api/v1/nodes/<node>/proxy/stats/summary). - It fails on GitHub but not here:
zeabur-oss-ci.
Version History
- e6ff195 Current 2026-11-02 08:50


