Skip to content

Clean up leaked GKE LoadBalancer firewall rules in setup-gke teardown#1367

Open
lsierant wants to merge 10 commits into
masterfrom
lsierant-gke-firewall-reaper
Open

Clean up leaked GKE LoadBalancer firewall rules in setup-gke teardown#1367
lsierant wants to merge 10 commits into
masterfrom
lsierant-gke-firewall-reaper

Conversation

@lsierant

@lsierant lsierant commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

[skip-ci] Clean up leaked GKE firewall rules + pin external-dns DNS zones in no-mesh GKE snippets

Summary

The private_gke_code_snippets tasks were failing at cluster creation with gcloud container clusters create returning 429 Insufficient project quota ... resource "FIREWALLS": ... quota of '500.0' with '0.0' available in the scratch-kubernetes-team project.

Root cause: when a GKE cluster is deleted, GKE removes its own managed firewall rules (gke-<cluster>-<hash>-*) but leaves behind the LoadBalancer Service firewall rules (k8s-fw-*, k8s-*-hc) created for Service objects of type LoadBalancer. Across many CI runs these accumulate and eventually exhaust the project-wide FIREWALLS quota, blocking all new GKE clusters.

This change:

  • Adds ra-01_9030_delete_firewall_rules.sh (run from ra-01-setup-gke/teardown.sh) to delete each run's leftover LB firewall rules, scoped to the run's own clusters via the node network tag so it never touches concurrent runs.
  • Adds ra-01_9020_delete_disks.sh to delete leftover persistent disks from PVCs with reclaimPolicy: Retain.
  • Pins external-dns to the per-run private Cloud DNS zone (--zone-id-filter, --domain-filter, --google-zone-visibility=private) in ra-09-setup-externaldns. Without this, leaked mongodb.custom. zones in the shared project caused external-dns to scatter AppDB A records into stale zones, making cluster 1/2 AppDB members unreachable and timing out the no-mesh snippet test.
  • Standardizes the multi-cluster OM wait_for_running timeouts at 1200s (ra-06 mesh + ra-10 no-mesh). The mesh test was failing at ra-06_0322 because the reconcile after adding the second member cluster (AppDB scale 3->5 + OM redeploy) regularly finished ~2-3 min after the old 600s wait expired.

Proof of Work

  • Latest PoW-Patch: https://spruce.mongodb.com/version/6a52014fc75a0100070d7d7fall green: unit_tests, and all 4 GKE snippet tests (public + private × mesh + no-mesh) passing concurrently.
    • Fixes the no-mesh om-certificate global-name collision by suffixing OM load balancer GCP resource names with K8S_CLUSTER_SUFFIX (commit 7fe5ffe), letting public and private no-mesh runs co-exist in one project.
    • external-dns zone-pinning fix and shareProcessNamespace revert both confirmed safe (AppDB + OM reached Running in no-mesh).

Checklist

  • Have you linked a jira ticket and/or is the ticket in the title?
  • Have you checked whether your jira ticket required DOCSP changes?
  • Have you added changelog file? (skip-changelog - CI tooling only, no customer-facing change)

@lsierant lsierant added the skip-changelog Use this label in Pull Request to not require new changelog entry file label Jul 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ (this preview might not be accurate if the PR is not rebased on current master branch)

MCK 1.9.2 Release Notes

Bug Fixes

  • MongoDBUser: Fixed a bug where the connection string Secret created in the central cluster did not carry a controller owner reference to the MongoDBUser CR. The missing reference prevented Kubernetes garbage collection from cleaning up the Secret when the MongoDBUser was deleted.
  • MongoDBUser: Fixed a bug where the ownership guard on the connection string Secret was always satisfied regardless of the actual owner, allowing the operator to silently overwrite a Secret controlled by a different resource.
  • Fixed a bug where all MongoDBCommunity deployment telemetry rows incorrectly reported IsRunningEnterpriseImage = true. The field was being evaluated against the operator-level enterprise image rather than the image configured in each CR's spec, causing a misleading ~100% enterprise rate for the Community deployment type.
  • IsRunningEnterpriseImage for Community deployments is now derived from the mongod container image override in spec.statefulSet.spec.template.spec.containers, if present. When no override is set, the field correctly defaults to false, reflecting that Community CRs use the community MongoDB server image by default.
  • MongoDBSearch: The default JVM heap size (half of the memory request) is now capped at 30GB, following the mongot sizing guidance. Heap sizes above ~30GB prevent the JVM from using compressed object pointers and degrade performance. User-provided heap flags are not affected, if more than 30GB heap is required, we recommend using jvmFlags.

GKE auto-deletes its managed firewall rules on cluster delete, but the
LoadBalancer Service firewall rules (k8s-fw-*, k8s-*-hc) are left behind and
accumulate across CI runs until they exhaust the project FIREWALLS quota,
failing 'gcloud container clusters create' with a 429. Delete each run's
leftover rules in ra-01-setup-gke/teardown.sh, matched by the node network tag.
@lsierant
lsierant force-pushed the lsierant-gke-firewall-reaper branch from 52e1bc8 to c83ece6 Compare July 10, 2026 14:14
@lsierant lsierant changed the title Reap leaked GKE firewall rules to prevent FIREWALLS quota exhaustion Clean up leaked GKE LoadBalancer firewall rules in setup-gke teardown Jul 10, 2026
lsierant added 8 commits July 10, 2026 16:40
The automation agent's StartFresh step races with the mongod container's
image pull: the agent runs 'mongod -f ...' inside the agent container
(where mongod is not installed), the process exits immediately, and the
agent enters a retry loop checking /data/mongod.lock. On the central
cluster the mongod container pulls its image quickly (~25s) and creates
the lock file before the agent gives up on that check pattern. On member
clusters the image pull takes ~54s, so the agent stops checking the lock
file before mongod starts and never recovers — the AppDB pods stay
not-ready forever, Ops Manager never reaches Pending, and the test times
out.

Fix: pre-pull the mongod image via a temporary DaemonSet on all three
GKE clusters before applying the OpsManager CR. Once the image is cached
on every node, the mongod container starts immediately and the agent
detects it via the lock file.
The automation agent detects mongod via /data/mongod.lock, but with
separate PID namespaces (the default for pods with init containers),
the PID written by the mongod container is unverifiable from the agent
container: PID 1 in the mongod container becomes PID 1 in the lock file,
but PID 1 in the agent container is the agent itself. The agent falls
back to connecting via the external domain, which never resolves on
member clusters where external-dns doesn't watch.

Setting shareProcessNamespace: true unconditionally makes the agent and
mongod share a PID namespace, so the agent can verify mongod's PID from
the lock file regardless of DNS state. This was already done for static
architectures; the normal path with init containers was missed.
Snippet generator wraps each file as 'function X() {' + contents + '}'.
Without a trailing newline the final 'done' glued to '}' producing 'done}',
a syntax error that broke GKE teardown ('.generated/...: syntax error:
unexpected end of file').
The temporary pre-pull DaemonSet was a workaround for the AppDB agent
timing race. It is redundant and is removed.
…s render

- Extract the inline LoadBalancer firewall-rule cleanup from teardown.sh into
  ra-01_9030_delete_firewall_rules.sh, run alongside the other ra-01_90xx
  teardown snippets.
- Render the external-dns manifest once into a variable and apply it per
  context, restoring the three symmetric kubectl apply lines.
The mesh GKE snippet test failed at ra-06_0322 (wait_for_running after
adding the second member cluster): the operator reached Running ~2.5 min
after the 600s wait expired. Adding a member cluster triggers a large
reconcile (AppDB scale 3->5 + OM redeploy across clusters) that regularly
exceeds 600s on GKE. Standardize all AppDB/OM wait_for_running timeouts at
1200s (0312 was 900s, 0322/0522 were 600s).
@lsierant
lsierant marked this pull request as ready for review July 10, 2026 21:19
@lsierant
lsierant requested a review from a team as a code owner July 10, 2026 21:19
…llisions

The no-mesh OM reference architecture created its global GCP load balancer
resources (ssl-certificate, forwarding-rule, target-https-proxy, url-map,
backend-service, health-check, firewall-rule) under fixed names. Two runs
sharing a project (e.g. public and private GKE snippet variants) collided on
these project-global names: the second create hit 'already exists' and one
run's teardown deleted the other's resources. Thread K8S_CLUSTER_SUFFIX
through the names via OM_LB_* env vars, matching how cluster names are made
unique. The suffix is empty by default, so documentation names are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changelog Use this label in Pull Request to not require new changelog entry file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant