Balis 情報マガジン

envtest

📅 October 29, 2026📖 Verified Publication
```html Envtest: The Complete Playbook for Testing Kubernetes Controllers — Key Takeaways, Checklist & FAQs

Envtest: The Complete Playbook for Testing Kubernetes Controllers

Key Takeaways

  • Envtest is the de facto standard for integration-testing Kubernetes controllers and custom APIs without needing a live cluster.
  • It boots a real etcd and apiserver in-process, giving you production-faithful test semantics at near-unit-test speed.
  • Pair envtest with Kubebuilder or controller-runtime's scheme registration for zero-boilerplate setup.
  • Common failure modes — missing CRD manifests, stale binary assets, race conditions in async controllers — are all preventable with a disciplined checklist.
  • For best ROI, reserve envtest for reconciler-level and CRD-level tests; use unit tests for pure logic and e2e tests for deployment-logic verification.

What Is Envtest?

Definition

envtest (short for "environment test") is a testing utility from the k8s.io/client-go ecosystem that spins up a minimal, in-process Kubernetes control plane — a real etcd instance and a real apiserver — during test execution. It lets Go developers exercise their controller logic against actual Kubernetes API machinery, including CRD discovery, scheme resolution, and the rest mapper, without provisioning a real cluster.

Why Envtest Matters

  • Faithfulness: Tests run against the same REST machinery that production controllers hit, catching regressions in serialization, validation, and CRD resolution that unit tests miss.
  • Speed: Startup is measured in seconds, not minutes, making it viable for CI pipelines on every pull request.
  • Isolation: Each test gets its own etcd instance, eliminating flaky cross-test state leakage.
  • No cluster required: Works on developer laptops, CI runners, and air-gapped environments.

Envtest Setup: Step-by-Step Playbook

Step 1 — Install the Envtest Binaries

Envtest ships as a standalone binary bundle (statically compiled etcd and apiserver). Download them once per Go module version.

  • Install the kubebuilder CLI: go install sigs.k8s.io/kubebuilder/cmd/kubebuilder@latest
  • Download the environment binaries matching your k8s.io/* dependency version: kubebuilder create api triggers automatic download, or run manually: kubebuilder assets download
  • Verify the binaries landed in the envtest data directory: ~/.local/share/kubebuilder-envtest/ (or $KUBEBUILDER_ASSETS target)

Step 2 — Configure Your Go Module

  • Ensure sigs.k8s.io/controller-runtime is at the same minor version as your k8s.io dependencies.
  • Add k8s.io/api, k8s.io/apimachinery, and k8s.io/client-go to go.mod.
  • Pin the k8s.io version — envtest binaries must exactly match the major.minor patch of the client libraries.

Step 3 — Register Your Scheme

  • Create a shared runtime.Scheme that registers every custom type your controller manages.
  • Call scheme.AddToScheme(scheme) for each group/version package.
  • Validate the scheme is complete: scheme.AllKnownTypes() should include every CRD type referenced in your tests.

Step 4 — Set Up the Envtest Control Plane

  • Set the KUBEBUILDER_ASSETS environment variable before any test runs.
  • In _test.go, use envtest.Environment to launch the control plane:
var env *envtest.Environment

func TestMain(m *testing.M) {
    cfg, err := envtest.Run(envtest.RunInput{
        CRDDirectoryPaths:     []string{"config/crd/bases"},
        ErrorIfCRDPathMissing: true,
        BinAssetsDir:          os.Getenv("KUBEBUILDER_ASSETS"),
    })
    // … wire cfg into your manager and run tests …
}

Step 5 — Write Your First Controller Test

  • Create the controller instance, injecting a client built from the envtest config.
  • Use testenv.Client (an client.Client backed by the in-process apiserver) for all CRUD operations.
  • Sleep or poll for reconciliation results using gomega.Eventually.
  • Clean up created objects with defer or within AfterEach.

Envtest Best-Practices Checklist

Before every envtest PR, run through this checklist to ensure your tests are reliable, fast, and maintainable.

# Checklist Item Priority Status Notes
1 Binaries match k8s.io dependency version exactly Critical ☐ Run kubebuilder assets download after any go get bump.
2 CRD manifests are valid YAML with correct apiVersion Critical ☐ Use kubectl apply --dry-run=server -f to validate.
3 KUBEBUILDER_ASSETS is set in CI configuration Critical ☐ Add to .github/workflows/ or Jenkinsfile.
4 Each test creates its own namespace (or uses t.Parallel()-safe isolation) High ☐ Prevents resource name collisions across parallel tests.
5 All created objects are cleaned up in defer or AfterEach High ☐ Orphaned objects leak into subsequent test runs.
6 Reconciliation waits use Eventually with a reasonable timeout (≥10 s) High ☐ Short timeouts cause flaky failures under CI load.
7 Controller reconciler is stubbed or mocked where appropriate (IO, external APIs) Medium ☐ Keep envtest focused on K8s-API interaction, not external behavior.
8 Tests run in parallel (t.Parallel()) where state is isolated Medium

© 2026 Balis 情報マガジン. All rights reserved.