Repository navigation
feat(gke-test): run every repository's tests on one shared GKE cluster - #32
Merged
Merged
Conversation
Local kind clusters fight for the same CPU and memory. This moves Kubernetes tests to the existing zonal cluster axiom-operator-acceptance, one namespace and one node pool per repository, with every pool at 0 nodes between runs. aw owns the cluster side: - infra/gke-test: Terraform that imports the cluster, its node service account, and the two old pools; adds system-pool (no autoscaling, woken and parked by script) and one tainted pool-<repo> per row of pools.yaml (0..max_nodes); adds the faberline-github WIF pool, one gke-test-<repo> service account per row, and the reaper identity. acceptance-pool loses autoscaling so pending kube-system pods cannot scale it up after a park. - infra/gke-test/bootstrap: the GCS bucket for the state. - .github/workflows/gke-test.yml: reusable workflow. It signs in through WIF, renders and checks the caller's k8s/overlays/gke-test, deploys, runs the caller's test command, and always tears down. - .github/workflows/gke-test-reaper.yml: every 30 minutes, deletes expired test namespaces and parks system-pool. - scripts/gke-test: run, teardown, wake, park, and reap in bash. - docs/standards/test-cluster.md: the guideline each repository follows. Nothing is applied yet; terraform plan shows 6 imports, 15 adds, 3 in-place updates, and 0 destroys.
…ing the axiom one The repositories moved from axiom to faberline, and a GKE cluster cannot be renamed. Terraform now creates faberline-test with its own node service account and only system-pool plus the pool-<repo> pools, so the imports, acceptance-pool, and data-plane-pool are gone. The old cluster is empty and is deleted by hand after this one is up. The cluster also uses the OPTIMIZE_UTILIZATION autoscaling profile, so an idle repository node goes away sooner. The project ID axiom-502607 stays; a project ID cannot change. The provider lock files are now tracked.
3 of 4 tasks
…budget So nothing on the shared test cluster keeps costing money unnoticed: - reap.sh also deletes orphan pvc-* disks (unattached, older than 1 hour, named by no PersistentVolume) and reports pods outside test and system namespaces without deleting them. It exits 1 when a person is needed. - The reaper workflow opens one issue on failure and closes it after the next clean run. - teardown.sh parks system-pool at the end, so the node does not wait for the next reaper run. - wake.sh waits for kube-dns Available instead of `rollout status`, which failed at once because the deployment passed its progress deadline while it sat Pending on 0 nodes (first keep run). - Terraform: a custom disk-reaper role, read access to PVs and pods for the reaper, and a monthly project budget (650 TWD) with 50/90/100% and forecast alerts. The billing account comes from the project data source.
chrischeng-c4
added a commit
to faberline/keep
that referenced
this pull request
Oct 15, 2026
faberline/aw#32 is merged, so the pilot no longer needs the feature branch. aw-ref defaults to main.
chrischeng-c4
added a commit
that referenced
this pull request
Oct 17, 2026
GitHub runs the reaper's */30 schedule every 2.5 to 5 hours, so system-pool stayed up for hours after the last test. Cloud Scheduler now starts the Cloud Workflows workflow gke-test-park every 10 minutes. It runs in GCP outside the cluster, does what park.sh does, and waits 5 minutes before it parks so it does not park between the suites of one run. The reaper stays as the second net. Also fix the reaper step list in test-cluster.md: step 4 lost its second line and step 5 its number in #32.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Local kind clusters fight for the same 10 CPU and 31 GB. This moves Kubernetes tests to a new zonal GKE cluster
faberline-test(projectaxiom-502607; a project ID cannot change): one namespace and one node pool per repository, and every pool at 0 nodes between runs.Who owns what
infra/gke-test/pools.yaml), identities, the shared workflow, the scripts, the reaperk8s/overlays/gke-test/, its image build to GHCR, its test commandWhat is in this PR
infra/gke-test/: Terraform. Creates the clusterfaberline-testand its node service account, with only these pools:system-pool: e2-standard-2 Spot, no autoscaling.wake.shsets it to 1;park.shsets it to 0.pool-<repo>for each row ofpools.yaml: 0..max_nodes, label and taintfaberline.dev/pool=<repo>.faberline-github(any repository underfaberline), onegke-test-<repo>service account per row, andgke-test-reaper.infra/gke-test/bootstrap/: the state bucketaxiom-502607-faberline-tfstate..github/workflows/gke-test.yml: reusable workflow. Render and check the overlay, deploy, run the test command, always tear down, upload evidence..github/workflows/gke-test-reaper.yml: every 30 minutes, delete expired test namespaces, parksystem-pool, delete orphanpvc-*disks, and report pods outside test namespaces. A failed run opens one issue; the next clean run closes it. It runs only after this PR is onmain.google_billing_budget.test, 650 TWD (about US$20) a month, emails at 50%, 90%, 100%, and 100% forecast. The billing account ID comes from the project, not from this public repository.scripts/gke-test/:run.sh,teardown.sh,wake.sh,park.sh,reap.sh.docs/standards/test-cluster.md: the guideline for repositories.Differences from the approved plan
cluster-admin, not a custom ClusterRole. A run creates ClusterRoles and bindings, which needsbindandescalate, which equalcluster-admin.axiom-operator-acceptance. The repositories moved from axiom to faberline, and a cluster cannot be renamed. The old cluster was empty and is deleted by hand.OPTIMIZE_UTILIZATIONautoscaling profile, so idle repository nodes go away sooner.system-poolis e2-standard-2, not e2-medium. kube-system requests about 700m plus DaemonSets.Checks
shellcheck -x -S warning scripts/gke-test/*.shactionlinton both workflowsterraform fmt -checkandterraform validateaxiom-502607-faberline-tfstateexists.terraform planagainst that bucket: 18 to add, 0 to change, 0 to destroy.run.shrender check, on a copy of keep: the template overlay fails with the 3 missing placement items; thegke-testoverlay passes. Teardown order is the exact reverse of the rendered order.terraform applyofinfra/gke-testwith owner approval: 18 added. A newterraform planshows no changes.pvc-*disks (331 GB) deleted; project display name is nowfaberline; old clusteraxiom-operator-acceptancedeleted.wake.sh(rollout statuson kube-dns hit its old progress deadline); teardown still deleted the namespace. Fixed withkubectl wait --for=condition=Available. Attempt 2 passed: readyz, round trip, and data survives a pod restart. Teardown parkedsystem-pool; afterwards the project had 0 VMs and 0 disks.terraform planfor the reaper and budget changes: 4 to add, 1 to change (reaper ClusterRole), 0 to destroy.terraform applyof the reaper and budget changes with owner approval: 4 added, 1 changed. A newterraform planshows no changes.🤖 Generated with Claude Code