Testing Kubernetes applications is notoriously challenging. Shared development environments lead to conflicts, traditional CI/CD pipelines can't replicate production complexity, and debugging failed tests in ephemeral containers feels like detective work.
What if every pull request you opened could spin up its own isolated Kubernetes environment with real GitOps workflows and comprehensive testing—then vanish when done?
This is exactly what we'll build using vCluster, ArgoCD, and Testkube. This solution expands on our previous post about End-to-End PR Testing in Kubernetes by adding ArgoCD as the deployment orchestrator, creating a complete GitOps pipeline where both infrastructure and tests are managed as code.
Traditional Kubernetes testing approaches fail at scale due to environment conflicts, infrastructure drift, and limited test observability. This architecture solves these problems by combining:
To achieve this, we will use the following tools:
Key Benefits
To understand this better, we'll build an automated testing system that creates isolated environments for every pull request.
When a developer opens a PR against our sample repository, GitHub Actions automatically:
Below is a sequence diagram to help you understand the sequence of events better.
To create the Testkube API token, refer to our API Token documentation. To find the Org ID and environment IDs, log in to your Testkube Dashboard and select Settings from the menu bar.
Further, we are using GKE for this demo, and we had to create some GitHub environment secrets with GKE cluster details like `GKE_PROJECT_ID`, `GKE_CLUSTER_NAME`, `GKE_ZONE`, and `GCP_SA_KEY` that are required to communicate with the GKE cluster.
You can find all the code, TestWorkflows, and manifests used in this blog post in this GitHub repo.
For this article we're using a simple nginx web application deployed via Kubernetes manifests (in real-life your application will most likely be much more complex). The application consists of a deployment, service, and ingress configuration. You can find all the nginx manifests here.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Our testing strategy combines performance and policy validation using two Testkube Workflows. You can create these TestWorkflows using the Testkube dashboard. You can also find these manifests here.
k6 Test Workflow
k6 is a load testing tool designed for testing APIs and web applications. Our k6 workflow simulates 10 concurrent users hitting the nginx service for 30 seconds, measuring response times and validating that the application can handle expected traffic loads without performance degradation. You can find the k6 TestWorkflow here.
kind: TestWorkflow
apiVersion: testworkflows.testkube.io/v1
metadata:
name: k6-sample
namespace: testkube
labels:
docs: example
spec:
content:
git:
uri: https://github.com/techmaharaj/testkube-vcluster-test.git
steps:
- name: Run Tests
workingDir: /data
run:
image: grafana/k6:0.49.0
env:
- name: K6_WEB_DASHBOARD
value: "true"
- name: K6_WEB_DASHBOARD_EXPORT
value: k6-test-report.html
shell: k6 run /data/repo/test/k6/k6-sample.js --vus 100 --duration 10s
artifacts:
paths:
- k6-test-report.html
status: {}
Chainsaw TestWorkflow
Chainsaw is a Kubernetes-native testing tool from the Kyverno project that validates cluster resources against policies and best practices. Our Chainsaw workflow verifies that the deployed nginx application has a certain number of replicas. You can find the actual Chainsaw TestWorkflow here.
kind: TestWorkflow
apiVersion: testworkflows.testkube.io/v1
metadata:
name: chainsaw-nginx
namespace: testkube
spec:
content:
git:
uri: https://github.com/techmaharaj/testkube-vcluster-test.git
paths:
- test/chainsaw
steps:
- name: Test ArgoCD deployment
workingDir: /data
run:
image: ghcr.io/kyverno/chainsaw:latest
shell: |
chainsaw test --report-format XML --report-path /data/repo --report-name chainsaw-report /data/repo/test/chainsaw
artifacts:
paths:
- /data/repo/chainsaw-report.xml
status: {}
Our GitHub Actions workflow orchestrates the entire testing pipeline through these key phases:
Below are the key implementation details. You can look at the complete GitHub Actions workflow file here. Please note that we have added logging and debug statements in the workflow to improve understanding and help with debugging should it fail.
vCluster Creation
- name: Create vCluster
run: |
echo "=== Creating vCluster for PR $PR_NUMBER ==="
# Save host context
HOST_CONTEXT=$(kubectl config current-context)
echo "HOST_CONTEXT=$HOST_CONTEXT" >> $GITHUB_ENV
echo "Host cluster context: $HOST_CONTEXT"
# Create namespace
kubectl create namespace demo-$PR_NUMBER --dry-run=client -o yaml | kubectl apply -f -
# Create vCluster with proper configuration
vcluster create testkube-vcluster-$PR_NUMBER \
--namespace demo-$PR_NUMBER \
--connect=false \
--expose
ArgoCD Integration
- name: Configure ArgoCD to Deploy to vCluster
run: |
echo "=== Configuring ArgoCD to Deploy to vCluster ==="
# Ensure we're on host cluster for ArgoCD operations
kubectl config use-context $HOST_CONTEXT
echo "Current context: $(kubectl config current-context)"
# Create ArgoCD application targeting vCluster
argocd app create nginx-vcluster-pr-$PR_NUMBER \
--repo "https://github.com/techmaharaj/testkube-vcluster-test" \
--path k8s \
--dest-server "$VCLUSTER_SERVER" \
--dest-namespace nginx \
--revision ${{ github.head_ref || github.ref_name }} \
--sync-policy automated \
--upsert
# Sync the application
argocd app sync nginx-vcluster-pr-$PR_NUMBER --force --timeout 300
Installing Testkube Runner
- name: Install Testkube Runner in vCluster
run: |
echo "=== Installing Testkube Runner in vCluster ==="
# Create unique runner name for this PR
RUNNER_NAME="vcluster-runner-pr-$PR_NUMBER"
echo "RUNNER_NAME=$RUNNER_NAME" >> $GITHUB_ENV
echo "Creating runner: $RUNNER_NAME"
# Install runner in vCluster - hardcode the known environment
echo "Installing runner with environment: testkube-gke"
testkube install runner "$RUNNER_NAME" \
--create \
--floating \
--label environment=vcluster \
--label pr_number="$PR_NUMBER" \
--label purpose=ephemeral_testing \
--namespace testkube \
--env testkube-gke
Executing TestWorkflow
- name: Run Tests in vCluster
id: run-tests
continue-on-error: true
run: |
# Runner Name
RUNNER_NAME="vcluster-runner-pr-$PR_NUMBER"
# Execute k6 test workflow targeting vCluster runner
testkube run testworkflow k6-sample -f \
--target name=$RUNNER_NAME \
--tag runner=$RUNNER_NAME \
--tag environment=vcluster \
--tag test-type=k6 \
--tag pr=PR-$PR_NUMBER \
--tag cluster=demo-$PR_NUMBER \
--tag demo=gitopscon-isolated
Workflow Triggers
The pipeline automatically triggers on:
With all the required steps in place, it’s time to see the workflow in action.
To trigger the workflow, simply create a new PR in the repo. The workflow begins immediately after PR creation and shows all steps in the Actions tab.
You will see the creation of vCluster on the GKE host cluster and the installation of ArgoCD on the host cluster.
ArgoCD deploys the nginx application directly from the PR branch to ensure we test the exact code changes.
The workflow first configures Teskube on the cluster using the API key, org ID, and env ID that you saved as variables.
Testkube runner is then installed on the Testkube environment that you associate it with using the credentials. You can also validate the runner setup under “Environments” on the Testkube dashboard.
Once this step is successful, you can see the Testkube runner created under “Settings” -> “Agents” on the Testkube dashboard.
After all the setup is ready and verified, the workflow executes the two Testworkflows - k6 and chainsaw - using the runner that we configured earlier.
Below is the successful execution of the k6 TestWorkflow that validated the nginx service.
Below is the chainsaw TestWorkflow that validated the number of replicas of the nginx deployment in the vCluster.
Once the execution is complete, you can check the status of the tests in the Testkube dashboard or in the GitHub actions workflow execution as well.
The status of the GitHub Action is automatically updated and sent back to the PR. For advanced use cases, you can create branch rules that can act based on the result of the GitHub Action.
With this we've built a complete GitOps testing pipeline that automatically creates ephemeral environments for every pull request. Our workflow provisions a vCluster, deploys applications using ArgoCD's GitOps principles, executes comprehensive tests with Testkube, and cleans up everything automatically—all without touching the host cluster. You can view the complete GitHub workflow here.
While our example used a simple Nginx deployment with basic K6 performance tests and Chainsaw policy validation, this architecture supports far more complex scenarios. You can integrate any Testkube-compatible testing framework, from Cypress end-to-end tests and Postman API collections to custom security scans and chaos engineering experiments.
The combination of ArgoCD, Testkube, and vCluster creates a robust GitOps testing machine that addresses the most fundamental challenges of testing in Kubernetes environments. By treating infrastructure, applications, and tests as code, this GitOps approach eliminates the environment conflicts, flaky tests, and infrastructure overhead that plague traditional testing workflows.
This is the next stage in cloud-native testing, transitioning from manual, shared test environments to declarative, automated, isolated, and ephemeral testing processes that match the speed of development.
Get started using Testkube and ArgoCD to create a modern, scalable PR testing workflow. Join the Testkube Slack community or read the Testkube documentation to begin creating your own automated testing stack!
Testkube is a test execution and orchestration framework for Kubernetes that works with any CI/CD system and testing tool you need. It empowers teams to deliver on the promise of agile, efficient, and comprehensive testing programs by leveraging all the capabilities of K8s to eliminate CI/CD bottlenecks, perfecting your testing workflow. Get started with Testkube's free trial today.
Related topics: