Tying Infrastructure to Git Events
The magic of ephemeral environments is that their entire lifecycle — creation, update, and destruction — is driven by Git events. Your CI/CD pipeline subscribes to webhooks from your Git provider (GitHub, GitLab, Bitbucket) and reacts accordingly. No human manually provisions or tears down anything.
Here is the complete lifecycle:
1. Creation (PR Opened)
When a developer opens a new PR:
- The pipeline builds a Docker image tagged with the specific commit SHA (e.g.,
myapp:abc1234). - It creates a unique, isolated Kubernetes Namespace (e.g.,
pr-123). A namespace is a logical partition inside a Kubernetes cluster — resources inpr-123cannot interfere with resources inpr-124. - It deploys the application into that namespace using a templating tool like Helm or Kustomize, substituting in the PR-specific image tag and hostname.
- It configures a dynamic Ingress rule — a routing rule that tells the cluster's load balancer to forward traffic from
pr-123.my-domain.comto the pods in thepr-123namespace. - A bot comments on the PR with the live URL, so reviewers can access it with one click.
2. Update (New Commit Pushed to the PR)
When the developer pushes a new commit to the same branch:
- The pipeline builds a new Docker image with the new commit SHA.
- It runs a
helm upgrade(or equivalent), which performs a rolling update of the pods in the existing namespace. The URL stays the same; the code underneath it changes.
3. Destruction (PR Closed or Merged)
This is the most important step. If you forget this, environments accumulate indefinitely and costs spiral out of control.
- The pipeline detects the
pull_request: closedevent. - It runs
kubectl delete namespace pr-123, which instantly wipes out every resource in that namespace: Pods, Services, ConfigMaps, Secrets, PersistentVolumeClaims, and Ingress rules. - The DNS entry for
pr-123.my-domain.comis removed (either automatically via ExternalDNS or via a cleanup script).
The Ingress Routing Pattern
The Ingress configuration is what makes the environment accessible from a browser. A wildcard DNS record (*.preview.example.com → cluster load balancer IP) combined with a wildcard TLS certificate means you can create arbitrarily many subdomains without touching DNS for each one. The Ingress controller (typically NGINX or Traefik) reads the Host header on incoming requests and routes to the correct namespace. The Ingress resource created per PR names its host, references a TLS secret managed by cert-manager, and routes all paths to the app's Service within that PR's namespace.
Interviewers often ask: "How do you handle TLS certificates for ephemeral environments?" The naive answer is "request a new cert per environment," which will immediately hit Let's Encrypt's rate limits (50 certs per registered domain per week). The correct answer is to use a wildcard certificate (*.preview.example.com) issued once and shared across all preview environments, managed by cert-manager. This is a common gotcha that separates candidates who have actually built this from those who have only read about it.