chore(nginx-gateway-fabric): take the chart to 2.7.0 - #443
Conversation
The Gateway API CRD bundle here is older than either release recommends, so the GatewayClass already reports SupportedVersion=False; 2.7.0 only changes which version that message names. TCPRoute and UDPRoute move to a v1 CRD check that this cluster does not satisfy, which drops controllers that were never watched here anyway. Merging rolls all five data-plane pods one node at a time behind a NodePort service with externalTrafficPolicy Local, so each node refuses connections while its pod restarts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jdwillmsen
left a comment
There was a problem hiding this comment.
Approved on jdwillmsen's instruction, posted by an agent session on their behalf.
The parked CRD concern does not block: this cluster already runs Gateway API bundle v1.1.0 against a recommended v1.5.1 and the GatewayClass already reports SupportedVersion=False; NGF compares major only, so v1.6.1 lands in the same bestEffort bucket and only the message string changes. TCPRoute/UDPRoute gate on a v1 CRD that is absent here, so those controllers are simply not registered — and they are not watched today either (no experimental-features flag, zero TCP/UDP/TLS routes). ReferenceGrant falls back to v1beta1 identically in both versions.
Accepted knowingly: the data-plane DaemonSet rolls all 5 pods at maxSurge: 0 behind a NodePort service with externalTrafficPolicy: Local, so each node refuses connections on 30180/30543 while its pod restarts. Merging now with the roll watched. 19/19 checks green.
Takes the
nginx-gateway-fabricchart from 2.6.7 to 2.7.0. Split out of #417 alongside #442 (argo-cd) so each lands on its own.The parked concern, and why it does not apply
This bump sat parked on the grounds that 2.7.0 needs Gateway API v1 TCPRoute/UDPRoute CRDs that this cluster does not have. The CRD gap is real; the conclusion is inverted.
The cluster is already in the degraded-but-working state, today, on 2.6.7.
bootstrap/crds/foundation-crds.yamlvendors 8 Gateway API CRDs, every one annotatedbundle-version: v1.1.0,channel: experimental, owned by theplatform-crdsApplication at sync-wave -1. 2.6.x recommends v1.5.1. So:NGF's
validateCRDVersionscompares major first and only flags a minor mismatch asbestEffort:v1.1.0 against 2.7.0's recommended v1.6.1 is the same arithmetic as v1.1.0 against v1.5.1 — major matches,
bestEffort. 2.7.0 changes the version this condition names and nothing else. Gateways stay Accepted and Programmed.TCPRoute and UDPRoute
2.7.0 moves them out of the
gwAPIExperimentalFeaturesblock and gates them on thev1CRD being served instead. Live discovery:The Kind is absent at
v1, so CRD discovery filters those controllers out of the registration list and their ObjectLists never enter the cache. No informer, no error, no crash.Nothing is lost, because they are not watched today either — the control-plane Deployment carries no
--gateway-api-experimental-featuresflag, and there is nothing to watch:ReferenceGrant behaves identically in both versions: the
v1controller is gated onv1presence (absent), and the object list falls back togatewayv1beta1.ReferenceGrantList. The per-namespaceallow-gateway-tlsgrants keep working exactly as they do now.Rendered chart delta with this tenant's values
2.6.7 → 2.7.0on the control-plane Deployment and, via NginxProxy, the data-plane DaemonSet--server-tls-domain=svc,--cluster-domain=cluster.localservices/statuspatch,policy/poddisruptionbudgets, and list/watch/status on tcproutes and udproutesmetricsport 9113 on the control-plane ClusterIP Service (the PodMonitor scrapes pods, so no conflict)pre-upgradealongsidepre-install, plus ahook-delete-policy. The Job itself already had both.certGenerator.overwritestays false, so no certificate churnexternalloadbalancersandpayloadprocessors, and additive schema fields on the existinggateway.nginx.orgCRDs.skipCrdsis not set in the tenant envelope and Argo CD already tracks all 11 of these CRDs as Synced resources, so they land automatically — no manual CRD apply stepChart.yaml kubeVersionfloor moves to>=1.32.0-0; the cluster is v1.36.3What it disrupts
The data-plane DaemonSet is created by the NGF controller, not by Helm, and rolls after the control plane comes up:
maxSurge: 0withexternalTrafficPolicy: Localmeans each node's NodePort refuses connections while that node's pod restarts, one node at a time. Whatever fronts these five NodePorts has to health-check the draining node out, or the roll surfaces as transient connection failures. There is also a short window where a 2.7.0 control plane drives a 2.6.7 data plane.Watch
kubectl -n nginx-gateway rollout status ds/platform-gateway-nginxthrough all five pods.Deliberately not included
Moving the Gateway API bundle v1.1.0 → v1.6.1 is a five-minor jump that changes served and storage versions on
referencegrants(currentlyv1beta1storage) and needs its own storage-version-migration plan and a freshness check. It is not a prerequisite for this upgrade: theSupportedVersion=Falsecondition predates this PR and simply continues to exist.Rollback
Revert the one line and let Argo CD sync;
prune: trueremoves the two new CRDs and no custom resources of those kinds exist. The data plane rolls back the same way. If the control plane is wedged and cannot reconcile,kubectl -n nginx-gateway rollout undo deploy/platform-nginx-gateway-fabricrestores 2.6.7 immediately — the existing DaemonSet keeps serving traffic throughout, since it does not depend on the control-plane pod.Worth an eye on the first sync
Whether Argo CD deletes the cert-generator hook SA/Role/RoleBinding at PreSync-phase completion rather than immediately. This was reasoned from the hook policies rather than observed; if deletion were immediate, the cert-generator Job could lose its RBAC mid-run.
🤖 Generated with Claude Code