Testing in Ephemeral vCluster Environments

Oct 13, 2026
read
Lakshmi Mukkur
Solutions Architect
Testkube
Read more from
Lakshmi Mukkur

Table of Contents

Start your free trial.

Start your free trial.

Start your free trial.

Explore Testkube hands-on.
30 days
no commitment
$0
no credit card needed

Subscribe to our monthly newsletter to stay up to date with all-things Testkube.

Please disable pixel blocker extension
You have successfully subscribed to the Testkube newsletter.
You have successfully subscribed to the Testkube newsletter.
Oops! Something went wrong while submitting the form.
Oct 13, 2026
read
Lakshmi Mukkur
Solutions Architect
Testkube
Read more from
Lakshmi Mukkur
Lakshmi Mukkur
Solutions Architect
Testkube
Per-feature vClusters speed up delivery but scatter testing. Here's how we ran tests inside each environment, started them from anything, and gated production with Testkube.

Table of Contents

Executive Summary

Giving each feature its own environment has become a common way to work. When a developer starts a feature, a vCluster is created for it. The feature runs there with its own copy of the services, and often the developers who build it now own its testing too.

Both changes help teams ship faster. Both also make testing harder to organize: there are now many environments, many people starting tests, and still one production to protect.

Three questions every team runs into

Once each feature has its own environment, the same three questions come up:

  1. Where do the tests run, so they can reach the feature’s services?
  2. What starts them: the pipeline, a deploy, or a person?
  3. How do you make sure only tested versions move on to production?

To answer them, we built a working setup in our lab. It has four feature vClusters on one cluster, a CI pipeline in Argo Workflows, Kargo for promotion, and Testkube for the tests. The rest of this post is what that setup taught us.

Diagram of a Testkube runner inside each of four feature vClusters and in staging, all connected to the Testkube control plane
The setup we built: a runner in every feature vCluster and in staging, all connected to the Testkube control plane.

Run the tests inside each environment

Tests that run inside the environment reach the app at its normal in-cluster address. There is no ingress, port-forward or public URL to set up for each feature, and nothing about the feature has to be exposed outside its vCluster.

In Testkube, the piece that runs tests is a runner. Whatever creates the vCluster also installs a runner inside it, as one Helm release. The runner connects out to the Testkube control plane on port 443, so no inbound ports are opened.

Two choices made this work smoothly:

  • Name the runner after the feature. A feature called feature-a gets a runner with feature-a in its name. Any tool that knows the feature name can then send its tests to the right place, with nothing to look up.
  • Size licenses by how many features test at once. Feature environments come and go, so their runners use floating licenses. A runner holds one only while it runs tests, and when all are busy, the next run waits in line and starts on its own. The number that matters is how many features test at the same moment, not how many vClusters exist.
Testkube runners list showing one floating-license runner per feature vCluster and one fixed-license runner for staging
The runners in our lab: one per feature vCluster with a floating license, labeled with its feature, and one runner with a fixed license that checks staging.

Write the tests once and let anything start them

When tests live inside the pipeline, every way of running them needs its own copy. Re-running one failed test means re-running the whole pipeline, and a deploy that skips the pipeline is never tested.

The fix is one test definition that says what to run, kept apart from what starts it. In Testkube that is a Test Workflow. Ours pulls the tests from the app’s Git repository, waits until every service answers its health check, runs 17 Playwright tests, and keeps the reports. The feature name is passed in when the run starts, so the same workflow serves every feature.

With one definition, anything can start the tests:

  • The CI pipeline, as one step that runs the tests on the feature’s runner and waits for the result. A failed test fails the pipeline. We used Argo Workflows; any CI that can run a command works the same way.
  • A deploy, through a trigger inside the vCluster. When a new version of the app rolls out, the runner starts the tests by itself, whatever tool did the deploy.
  • A promotion tool, before a version moves on. The next section covers this.
  • A person, from the dashboard or the command line, or a schedule.

In the lab, every one of these ran the same Test Workflow. Only two values changed per run: the feature name and the runner. From the command line, a run looks like this:

testkube run testworkflow vcluster-e2e-inside --config feature=feature-a --target name=feature-a-runner-testkube-runner --watch

Gate promotion in an environment that stays up

Feature environments find problems early, but they come and go. The check that protects production belongs in an environment that stays up and looks like production: staging.

The pattern is simple. A promotion tool moves a new version to staging, runs the tests there, and lets production take only versions that passed. In our lab, Kargo did the promotion, and its verification step after each promotion to staging was a Testkube run. A version that failed stayed in staging, and the production stages never saw it.

Staging lives as long as production does, so its runner uses a fixed license. Tests there start the moment they are triggered, with no waiting in line. The same check can also run after a production deploy, as a smoke test.

Kargo Verifications tab for the staging stage showing three passed verification runs, each about a minute long
Kargo's verification history for staging: each promotion checked by a Testkube run.

Keep every result in one place

With many environments and many ways to start tests, results scatter quickly: a log in one pipeline run, a job output somewhere else. It gets hard to say how a feature’s tests have gone this week.

Keep every result in one place, tagged with the environment each run tested. In Testkube, every run lands in the same list, whether the pipeline, a trigger or the promotion check started it. A filter on the feature tag shows one environment’s history. Each run keeps its logs and reports, such as the Playwright report and the JUnit results.

Testkube execution list for one Test Workflow with each run tagged by the feature environment it tested
Runs of the same Test Workflow, each tagged with the environment it tested and run on that environment's own runner.
Testkube execution detail showing a Playwright HTML report and JUnit results saved as artifacts
One run, with its Playwright report and JUnit results kept as artifacts.

What we learned

  • Use one name everywhere. The vCluster, its runner and the tag on each run all carry the feature name, so every tool can find the others without a lookup.
  • Make cleanup part of teardown. Deleting a vCluster removed the runner’s pods, but not the runner’s entry in Testkube. Our teardown step removes both.
  • Check that the app is ready before testing. A short readiness step that waits for every service keeps a slow start from showing up as a failed test.
  • Tell the runner which namespaces to watch. A deploy trigger only sees changes in namespaces the runner watches, so include the app’s namespace when you install it.
  • Expect the first run in a new environment to be slower. It pulls the test image and took about a minute in our lab. Later runs took about 30 seconds.
  • Keep feature names short. One name becomes a vCluster, a namespace, a Helm release and a runner, and Kubernetes limits most names to 63 characters.

Learn more

Each piece of this setup has a page in the Testkube docs:

{{banner-get-started}}

Lakshmi Mukkur
Solutions Architect
Testkube
Read more from
Lakshmi Mukkur

About Testkube

Testkube is the open testing platform for AI-driven engineering teams. It runs tests directly in your Kubernetes clusters, works with any CI/CD system, and supports every testing tool your team uses. By removing CI/CD bottlenecks, Testkube helps teams ship faster with confidence.
Get Started with a trial to see Testkube in action.