Back to Blog
Software EngineeringTechnologyJune 18, 20263 min read

Ephemeral Environments with vcluster and GitHub Actions Guide

Master ephemeral environments for pull requests using vcluster and GitHub Actions. Learn how to spin up isolated Kubernetes namespaces for faster testing.

kubernetesvclusterdevopsgithub-actionscloud-nativeci-cdautomationLinuxServer

If you’ve ever spent hours debugging a "works on my machine" issue that failed in staging, you know the pain of shared dev environments. They are bottlenecks. Someone deletes a configmap, or a migration goes sideways, and suddenly nobody can work.

I started using ephemeral environments to solve this. By spinning up a fresh, isolated Kubernetes cluster for every pull request preview, we eliminate contention. But spinning up a full EKS or GKE cluster for every PR is expensive and slow. That’s where vcluster changes the game.

Why vcluster for PR Previews?

Standard namespaces are fine, but they don't provide true isolation. If you need custom CRDs, different API versions, or cluster-wide permissions, a namespace won't cut it.

vcluster creates a virtual cluster inside your existing Kubernetes cluster. It’s lightweight, fast, and uses a fraction of the resources of a "real" cluster. Since it runs as a pod, you can spin one up in seconds.

The Architecture

We’ll use GitHub Actions to trigger the creation of a vcluster whenever a PR is opened.

  1. Trigger: PR opened or synchronized.
  2. Setup: Install vcluster CLI and helm in the runner.
  3. Deploy: Create the virtual cluster.
  4. Sync: Deploy the application manifests into the virtual cluster.
  5. Teardown: Delete the vcluster when the PR is closed.

Implementation Guide

First, make sure you have the vcluster CLI installed in your runner. I prefer using the official setup action.

YAML
# .github/workflows/ephemeral.yml
name: PR Ephemeral Environment

on:
  pull_request:
    types: [opened, synchronize, closed]

jobs:
  vcluster-lifecycle:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install vcluster
        run: curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64" && sudo install -c -m 0755 vcluster /usr/local/bin

      - name: Create vcluster
        if: github.event.action != 'closed'
        run: |
          vcluster create pr-${{ github.event.number }} --namespace pr-${{ github.event.number }}
          vcluster connect pr-${{ github.event.number }} --kubeconfig=./kubeconfig.yaml

      - name: Deploy App
        if: github.event.action != 'closed'
        run: |
          export KUBECONFIG=./kubeconfig.yaml
          kubectl apply -f k8s/deployment.yaml

      - name: Cleanup
        if: github.event.action == 'closed'
        run: vcluster delete pr-${{ github.event.number }}

Key Considerations for Cloud-Native Development

When you move to this model, you'll hit a few hurdles. Here is how I handle them:

1. Ingress and DNS

How do you access the app? I use ingress-nginx with a wildcard domain. Each vcluster gets a unique subdomain: pr-123.dev.example.com. You’ll need to configure your Ingress controller to route requests based on the host header.

2. Resource Quotas

Don't let a stray PR consume your entire node pool. Always set resource limits on the namespace where the vcluster runs.

YAML
apiVersion: v1
kind: ResourceQuota
metadata:
  name: vcluster-quota
spec:
  hard:
    requests.cpu: "2"
    requests.memory: 4Gi

3. Persistent Storage

If your app needs a database, don't spin up a managed RDS instance for every PR. It’s too expensive. Use a lightweight operator like Postgres Operator inside the vcluster or use a shared, pre-provisioned dev database instance.

The "Hard-Won" Lessons

I’ve seen teams try to implement this and fail because they forgot about clean-up. GitHub Actions are great, but if a workflow fails, the cleanup step might not run.

Pro-tip: Use a Kubernetes "Janitor" or a TTL controller. I use the loft CLI or a simple cron job that deletes any namespace prefixed with pr- that hasn't been updated in 24 hours. Never rely solely on the GitHub Actions lifecycle for infrastructure cleanup.

Final Thoughts

Integrating vcluster into your CI/CD pipeline is the single most effective way to improve developer velocity. It gives your team the freedom to break things without affecting their peers. It’s not just about cool tech; it's about removing the fear of deployment.

Start small. Try it on one microservice. Once you see the feedback loop tighten, you won't ever want to go back to shared staging environments.

Similar Posts