Skip to content

Upgrading

This section documents version-to-version upgrade paths and the breaking changes that go with each release line.

Available guides

  • v2 → v3 — the v3 chart collapses to a single L7-proxy data plane, slims the GatewayClassConfig CRD spec, drops the AmneziaWG sidecar, and tightens RBAC.
  • v3.0 or v3.1 → v3.2 — multi-tenant isolation hardening: data-plane metrics and config-API NetworkPolicy default on, a new RouteShadowed condition/Event, and a longer proxy drain window. The new GatewayConfig CRD must be applied by hand, the Gateway API CRDs move to a v1.6 bundle, and manual (non-Helm) installs need new ClusterRole rules. No values change is needed except in the two setups the guide names: a CNI that enforces host-to-pod traffic, where the default-on policy takes proxy readiness down, and an install that already enabled the proxy NetworkPolicy and relied on its egress restriction.
  • v3.4 → v3.5 — changes that can break a working setup, some needing a values edit; the guide covers the rest of what changed. The NetworkPolicies guarding the proxies' config-API port now admit the controller pod rather than its whole namespace, and because proxy.networkPolicy.enabled defaults to true this reaches an install that never set the key: on a NetworkPolicy-enforcing CNI, a scraper sharing the release namespace loses the proxies' /metrics until it is admitted through proxy.networkPolicy.ingress.from for the shared proxy, or proxy.networkPolicy.monitoringNamespaceSelector for per-Gateway data planes; and a values file with networkPolicy.enabled: true and networkPolicy.cloudflareIpRanges emptied now stops the render. The GatewayClassConfig CRD also needs a one-time re-apply (see CRD upgrades).
  • v3 → v4 — tightened defaults, TLS on the config API, and route binding, listener conflicts and status reporting brought in line with the Gateway API spec. The chart needs Kubernetes 1.31. Among the changes that can stop traffic: the config API, the proxy's probes and its /metrics speak HTTPS by default, so an image pinned to v3 or a scrape config of your own needs attention; two of a Gateway's own listeners that conflict are both refused; a parentRef with group: "" no longer binds; a --proxy-endpoints Service you bring yourself needs publishNotReadyAddresses: true; and with networkPolicy.enabled the controller admits no in-cluster source until it is listed. Many condition reasons and counts change as well. Read every section headed Breaking before upgrading.
  • v4 → v5 — routing, status and backend TLS brought in line with the Gateway API spec; no chart value, CRD or RBAC change. Among the changes that can change what is served: listener isolation, so a route on a wildcard or hostname-less listener stops answering hostnames a more specific listener owns; a Gateway with spec.tls.frontend or a non-Hostname spec.addresses entry is refused; route matches are ranked one match at a time; a scheme-less redirect takes the listener port; ServiceImport backends no longer take a same-named Service's BackendTLSPolicy; and HTTPRoute retry takes effect. A failed tunnel document write no longer changes route status, so a broken Cloudflare credential shows only in Events, metrics and logs. Read every section headed Breaking before upgrading.

Conventions

  • Each guide lists the breaking changes and the steps to migrate, in order.
  • "No data migration is required for CRs" means existing CRs continue to work; the API server prunes any fields the new schema no longer declares.
  • helm upgrade --reset-then-reuse-values is preferred over --reuse-values when the new chart adds a required value — the latter drops new chart defaults and the install fails on the required check.

CRD upgrades

Helm installs the files under the chart's crds/ directory only on the FIRST helm install; helm upgrade deliberately never touches them. Apply the CRDs once before upgrading to a chart version that adds a CRD (for example GatewayConfig for per-Gateway data planes, which the v3.2 controller watches from startup) or that adds a field to an existing one.

A field the installed CRD does not declare is pruned by the apiserver on write, with no error and no Event: it disappears on the way in and reads back unset, so a setting you made is not in force. When the controller starts, it logs an error for each field that the installed GatewayClassConfig, GatewayConfig or ExternalBackend CRD does not declare.

kubectl apply \
  --filename https://raw.githubusercontent.com/lexfrei/cloudflare-tunnel-gateway-controller/master/charts/cloudflare-tunnel-gateway-controller/crds/cf.k8s.lex.la_gatewayclassconfigs.yaml \
  --filename https://raw.githubusercontent.com/lexfrei/cloudflare-tunnel-gateway-controller/master/charts/cloudflare-tunnel-gateway-controller/crds/cf.k8s.lex.la_gatewayconfigs.yaml \
  --filename https://raw.githubusercontent.com/lexfrei/cloudflare-tunnel-gateway-controller/master/charts/cloudflare-tunnel-gateway-controller/crds/cf.k8s.lex.la_externalbackends.yaml