Docs
HelmInstallation

Upgrading

Upgrade procedures for the netbox-enterprise Helm chart

Installation Journey PrerequisitesInstallUpgrading (you are here)

This guide covers how to upgrade NetBox Enterprise to a new chart version, including CRD updates and rollback procedures.

Pre-Upgrade Checklist

Before upgrading:

  1. Review the release notes for the target version
  2. Back up your database - see Backups if using Velero
  3. Verify current state - ensure all components are healthy:
kubectl -n netbox get netboxenterprises
kubectl -n netbox get pods
  1. Check for breaking changes in values.yaml between versions
  2. Rehearse the CRD upgrade without touching the cluster. helm upgrade --dry-run runs Helm's ownership check, so it surfaces the 2.3.0 adoption step below before you commit to anything. Name a CRD chart you actually have: on external PostgreSQL you have no netbox-enterprise-crds-pgo release, on external Redis no netbox-enterprise-crds-redis, and without the bundled gateway neither -gateway nor -traefik. Do not use netbox-enterprise-crds here, since it is the one chart that needs no adoption and so proves nothing.
helm upgrade netbox-enterprise-crds-redis \
  oci://registry.enterprise.netboxlabs.com/netbox-enterprise/stable-v2/netbox-enterprise-crds-redis \
  --version 2.3.0 --namespace netbox --dry-run

A release you do not have reports Error: UPGRADE FAILED: "<release>" has no deployed releases; pick a different chart. This works on any Helm version.

Upgrade the Chart

1. Upgrade CRDs

Upgrade the CRD charts before the operator.

Coming from 2.2.x or earlier, your first 2.3.0 upgrade of most of these charts needs --take-ownership. The next section says which and why; the commands below already include it.

REGISTRY=oci://registry.enterprise.netboxlabs.com/netbox-enterprise/stable-v2
VERSION=2.3.0

# Already Helm-owned, so no adoption flag is needed here.
helm upgrade netbox-enterprise-crds "$REGISTRY/netbox-enterprise-crds" \
  --version "$VERSION" --namespace netbox

# Adopt on the first 2.3.0 upgrade. Drop --take-ownership afterwards.
# Skip either chart if you use external PostgreSQL or external Redis.
for CHART in netbox-enterprise-crds-pgo \
             netbox-enterprise-crds-redis; do
  helm upgrade "$CHART" "$REGISTRY/$CHART" \
    --version "$VERSION" --namespace netbox \
    --take-ownership
done

# Only if you installed the bundled gateway. Read the warning below first.
for CHART in netbox-enterprise-crds-gateway \
             netbox-enterprise-crds-traefik; do
  helm upgrade "$CHART" "$REGISTRY/$CHART" \
    --version "$VERSION" --namespace netbox \
    --take-ownership
done

A chart you do not have reports Error: UPGRADE FAILED: "<release>" has no deployed releases. That is expected for any chart you never installed; skip it and move on.

Always upgrade CRDs before running helm upgrade on the operator. CRDs define the schema for the NetBoxEnterprise resource - upgrading the operator without updating CRDs can cause validation errors.

One-time step when upgrading to 2.3.0

The first 2.3.0 CRD upgrade needs an extra flag

Upgrading from any earlier version, the first helm upgrade of each vendored CRD chart has to adopt the CRDs your previous release installed. Without --take-ownership the upgrade aborts and the release stays on its old revision:

Error: UPGRADE FAILED: Unable to continue with update: CustomResourceDefinition
"redis.redis.redis.opstreelabs.in" in namespace "" exists and cannot be imported
into the current release: invalid ownership metadata;
  label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"

Nothing is partially applied when this happens. The chart is untouched and you can retry.

Which charts need it:

ChartFirst upgrade to 2.3.0
netbox-enterprise-crdsno flag needed
netbox-enterprise-crds-pgoadd --take-ownership
netbox-enterprise-crds-redisadd --take-ownership
netbox-enterprise-crds-gatewayadd --take-ownership, if installed
netbox-enterprise-crds-traefikadd --take-ownership, if installed

The charts are independent releases, so you can run them one at a time and re-run any that succeeded; a repeat upgrade with no flag is a no-op.

Embedded Cluster and KOTS installs need no action here. The installer passes the flag for you, provided kotsadm is at least 1.124.0, the first version to bundle a Helm that understands it.

Check who owns the Gateway API and Traefik CRDs first

--take-ownership makes Helm adopt a matching CRD whoever installed it, then apply our schema over theirs. For pgo and redis that is safe: those API groups are ours. The gateway.networking.k8s.io and traefik.io groups are not. If Istio, Cilium, Envoy Gateway or your own Traefik installed them, adopting transfers them to our release, replaces their schema with our vendored one, and their owning release is never told.

Ownership is recorded per CRD, not per group, so check all of them rather than a sample. A cluster where another controller owns only some members of a group will pass a spot check and fail you on the rest.

for crd in backendtlspolicies gatewayclasses gateways grpcroutes \
           httproutes listenersets referencegrants tlsroutes; do
  printf '%-24s %s\n' "$crd" \
    "$(kubectl get crd "$crd.gateway.networking.k8s.io" \
        -o jsonpath='{.metadata.annotations.meta\.helm\.sh/release-name}' 2>/dev/null || echo '(absent)')"
done

for crd in ingressroutes ingressroutetcps ingressrouteudps middlewares \
           middlewaretcps serverstransports serverstransporttcps \
           tlsoptions tlsstores traefikservices; do
  printf '%-24s %s\n' "$crd" \
    "$(kubectl get crd "$crd.traefik.io" \
        -o jsonpath='{.metadata.annotations.meta\.helm\.sh/release-name}' 2>/dev/null || echo '(absent)')"
done

Every line must be blank, (absent), or our own netbox-enterprise-crds-gateway / netbox-enterprise-crds-traefik. If any line names another release, do not adopt that chart.

What to do instead. Leave that CRD chart on its current version and upgrade the rest. You lose nothing: the vendored Gateway API and Traefik CRDs are byte-identical between 2.2.1 and 2.3.0, all 18 of them, so there is no schema change to miss. Skipping the upgrade for a chart another controller owns is the correct outcome, not a workaround, and NetBox Enterprise keeps using whichever Gateway API CRDs the cluster already has.

Embedded Cluster is unaffected, since NetBox Enterprise is the only Gateway API provider there.

netbox-enterprise-crds has always shipped its CRD from templates/, so Helm already owns it.

Helm applies a crds/ directory without recording that it owns the result, so CRDs installed by an earlier release carry no ownership metadata. The charts deliver those same CRDs from templates/, so Helm expects to own them and refuses to take over an unowned object until you say so.

Adoption is a one-time step

Once the metadata is recorded, later upgrades of these charts succeed with no flag. Do not leave --take-ownership in a runbook: it disables Helm's ownership check on every run, so a CRD another controller has claimed would be taken over silently instead of stopping the upgrade.

Existing custom resources are not affected. Adoption records ownership metadata on the CRD; it does not touch the objects the CRD defines, and the stored API version is unchanged.

To confirm adoption landed, list any CRD that is still unowned. Empty output means every one is accounted for:

kubectl get crd -o json | jq -r '
  .items[]
  | select(.metadata.name | test("opstreelabs.in$|crunchydata.com$|gateway.networking.k8s.io$|traefik.io$|netboxlabs.com$"))
  | select(.metadata.annotations["meta.helm.sh/release-name"] == null)
  | .metadata.name'

A missed CRD also fails the very next helm upgrade of that chart, so this is a convenience rather than the only signal.

If your Helm client is older than 3.17

--take-ownership arrived in Helm 3.17. An older client rejects it outright with Error: unknown flag: --take-ownership. Apply the same metadata with kubectl instead, then upgrade normally. The --dry-run rehearsal above still works on these clients and still reports the ownership error, so you can confirm the problem before fixing it.

Name the CRDs explicitly. Do not select them with a group-wide grep: the gateway.networking.k8s.io and traefik.io groups can also hold CRDs installed by another controller such as Istio, Cilium, or Traefik Hub, and stamping our release name onto one of those breaks that controller's own helm upgrade.

NAMESPACE=netbox

adopt() {                      # adopt <release> <crd>...
  local release=$1; shift
  for crd in "$@"; do
    kubectl label crd "$crd" app.kubernetes.io/managed-by=Helm --overwrite
    kubectl annotate crd "$crd" \
      meta.helm.sh/release-name="$release" \
      meta.helm.sh/release-namespace="$NAMESPACE" --overwrite
  done
}

adopt netbox-enterprise-crds-pgo \
  pgadmins.postgres-operator.crunchydata.com \
  pgupgrades.postgres-operator.crunchydata.com \
  postgresclusters.postgres-operator.crunchydata.com

adopt netbox-enterprise-crds-redis \
  redis.redis.redis.opstreelabs.in \
  redisclusters.redis.redis.opstreelabs.in \
  redisreplications.redis.redis.opstreelabs.in \
  redissentinels.redis.redis.opstreelabs.in

# Only if you installed the bundled gateway.
adopt netbox-enterprise-crds-gateway \
  backendtlspolicies.gateway.networking.k8s.io \
  gatewayclasses.gateway.networking.k8s.io \
  gateways.gateway.networking.k8s.io \
  grpcroutes.gateway.networking.k8s.io \
  httproutes.gateway.networking.k8s.io \
  listenersets.gateway.networking.k8s.io \
  referencegrants.gateway.networking.k8s.io \
  tlsroutes.gateway.networking.k8s.io

adopt netbox-enterprise-crds-traefik \
  ingressroutes.traefik.io \
  ingressroutetcps.traefik.io \
  ingressrouteudps.traefik.io \
  middlewares.traefik.io \
  middlewaretcps.traefik.io \
  serverstransports.traefik.io \
  serverstransporttcps.traefik.io \
  tlsoptions.traefik.io \
  tlsstores.traefik.io \
  traefikservices.traefik.io

NAMESPACE and each release name must match the Helm releases you are upgrading. Then run the helm upgrade commands above without --take-ownership.

2. Upgrade the Operator

helm upgrade netbox-enterprise \
  oci://registry.enterprise.netboxlabs.com/netbox-enterprise/stable-v2/netbox-enterprise \
  --version 2.3.0 \
  --namespace netbox \
  --values netbox-values.yaml

Monitor the Upgrade

Watch the operator reconcile with the new version:

kubectl -n netbox get pods -w

Check the operator logs for reconciliation progress:

kubectl -n netbox logs -l app.kubernetes.io/name=nbe-operator -f --tail=50

Verify the upgrade completed:

kubectl -n netbox get netboxenterprises -o wide

The VERSION column should reflect the new operator version.

Check Release Status

helm status netbox-enterprise --namespace netbox
helm history netbox-enterprise --namespace netbox

Rollback

If the upgrade causes issues, roll back to the previous release:

helm rollback netbox-enterprise --namespace netbox

To roll back to a specific revision:

helm history netbox-enterprise --namespace netbox
helm rollback netbox-enterprise <revision-number> --namespace netbox

Rolling back the netbox-enterprise release reverts the operator deployment and values. It does not touch CRDs; those live in their own releases.

Rolling a CRD chart back below 2.3.0 does not restore the older schema. Those releases delivered their CRDs from crds/, which Helm never records in the stored manifest, and every CRD carries helm.sh/resource-policy: keep, so helm rollback neither re-applies the old schema nor removes the current one. The live CRDs keep their 2.3.0 schema and simply stop being tracked by the release. Roll the operator back and leave the CRD charts where they are.

Suspend Reconciliation

If you need to pause the operator during troubleshooting without rolling back:

helm upgrade netbox-enterprise \
  oci://registry.enterprise.netboxlabs.com/netbox-enterprise/stable-v2/netbox-enterprise \
  --version 2.3.0 \
  --namespace netbox \
  --reuse-values \
  --set netboxEnterprise.spec.suspend=true

The operator will stop reconciling the NetBoxEnterprise until suspend is set back to false. Existing workloads continue running.

Next Steps

On this page