Upgrade Guide¶
v1.13.0 is the first public release of this independent project. There is no upgrade path from earlier version numbers — install v1.13.0 fresh (see the Installation guide).
This is a personally maintained, community project with no affiliation to Neo4j, Inc. APIs and behaviour may change between releases — review the release notes before upgrading, and validate independently before relying on a new version.
v1.14 — backup & restore API cleanup (breaking)¶
v1.14 removes the deprecated Neo4jBackup / Neo4jRestore fields that v1.13
kept working behind deprecation warnings. v1beta1 is still a beta API, so these
are removed in place rather than versioned. Update your Neo4jBackup and
Neo4jRestore manifests before upgrading — the removed fields are silently
dropped by the API server (they're no longer in the CRD schema), which would
otherwise leave a backup/restore mis-scoped or unconfirmed.
Nothing else changes: cluster, standalone, database, user/role, and plugin CRs are untouched.
Neo4jBackup¶
| Removed | Replacement |
|---|---|
spec.target.{kind,name,clusterRef} |
spec.instanceRef + exactly one of spec.database / spec.allDatabases / spec.shardedDatabase |
spec.cloud (top-level) |
spec.storage.cloud |
spec.options.verify |
(removed — it was never wired to neo4j-admin backup validate; use spec.options.validate) |
spec.retention.deletePolicy: Archive |
Delete (the only supported value; Archive never had archival logic) |
# BEFORE (v1.13) # AFTER (v1.14)
spec: spec:
target: instanceRef: my-cluster
kind: Cluster allDatabases: true
name: my-cluster storage:
cloud: type: s3
provider: aws bucket: backups
storage: cloud:
type: s3 provider: aws
bucket: backups
Scope mapping: kind: Cluster → allDatabases: true; kind: Database (with
name: db, clusterRef: c) → instanceRef: c + database: db;
kind: ShardedDatabase (with name: sd, clusterRef: c) → instanceRef: c +
shardedDatabase: sd.
Neo4jRestore¶
| Removed | Replacement |
|---|---|
spec.clusterRef |
spec.instanceRef |
spec.databaseName |
spec.database |
spec.force |
spec.options.replaceExisting: true |
spec.verifyBackup |
(removed — it was never implemented) |
# BEFORE (v1.13) # AFTER (v1.14)
spec: spec:
clusterRef: my-cluster instanceRef: my-cluster
databaseName: orders database: orders
force: true options:
source: replaceExisting: true
type: backup source:
backupRef: nightly type: backup
backupRef: nightly
Also new in v1.14 (additive, no action needed): Neo4jRestore.status.stats.duration
and status.backupInfo are now populated on a successful restore.
Upgrading from v1.16.x¶
Apply the new release's CRDs before upgrading the operator (step 1
below). This release needs them for more
than new fields: learn mode keeps its state in new Neo4jRole status fields,
and without the CRDs every Neo4jRole goes Failed saying so. No privilege is
removed in that state.
Neo4jRole: privileges are matched by learn mode (behaviour change)¶
Neo4j stores a privilege differently from how it is written (NODES becomes
NODE, lists become one row per item, aliases resolve to their target). The
operator used to compare the text, which toggled some privileges off on every
other reconcile. It now compares against what Neo4j stores, learned from its
own grants — learn mode, the new default; see
Privilege drift reconciliation.
What you will see on upgrade: every existing role reports
PrivilegesSynced=Unknown (reason UnattributedPrivileges), because learn
mode cannot attribute rows that were already there. Nothing is revoked and
access is unchanged; the difference is that out-of-band additions to those rows
are not removed until you clean them up. To restore full enforcement on a
role, remove unwanted rows by hand or delete and recreate the Neo4jRole. If
you would rather have exact attribution immediately and can accept short-lived
operator_privilege_probe_* roles in Neo4j's security log, set the Helm value
privilegeNormalisation: probe.
Sharding no longer sets the server's Cypher language¶
Enabling property sharding used to set db.query.default_language=CYPHER_25
for the whole server. It no longer does: sharded databases get Cypher 25 on
their own, and the server default is the new
spec.serverDefaultCypherLanguage. Existing clusters are unaffected — the
operator records what each one already runs and keeps writing it, so the
upgrade restarts nothing. See the
property sharding guide.
New, no action needed¶
spec.serverDefaultCypherLanguageon clusters and standalones — see Configuration. Existing deployments keep their current language.spec.privilegeRulesonNeo4jRole: privileges as fields instead of Cypher.- Remote composite constituents with stored credentials now work on the 5.26
LTS; they failed there in v1.16.0. Their URL must be
neo4j+s://orneo4j+ssc://, which is now checked at apply time. spec.graphAnalyticsonAuraInstance:unavailable,pluginorserverless. Serverless graph analytics is created through Aura's v2beta1 API. See the AuraInstance API reference.
Deprecated¶
AuraInstance.spec.graphAnalyticsPlugin— usespec.graphAnalytics. It keeps working and maps toplugin(true) orunavailable(false). Setting both is refused. An existing instance may switch to the equivalentgraphAnalyticsvalue; setting any othergraphAnalyticsvalue is refused, because Aura cannot change it after creation. Editing or removing the boolean itself is accepted but has no effect on an existing instance, which only reads it at creation.
Upgrading from v1.17.x¶
Apply the new release's CRDs before upgrading the operator, as always (step 1
below). Nothing fails without them, but
status.upgradeStatus.phaseStartTime is new: on the old CRDs the API server
drops it, and neo4j_operator_upgrade_duration_seconds records nothing until
the CRDs are applied.
Behaviour changes¶
- Scheduled backups report
Ready=True(reasonBackupScheduled). ANeo4jBackupwith ascheduleused to stayReady=Unknownfor its whole life, sokubectl wait --for=condition=Readynever returned. A suspended one now reportsReady=Falsewith reasonSuspendedinstead ofReconciliationFailed. - If you use the ArgoCD health checks, re-apply
docs/gitops/argocd-health-checks.yaml. In the copy published with v1.17.0, a scheduled or suspendedNeo4jBackupstayedProgressingforever, which holds up any sync wave behind it. Both now reportHealthy. Neo4jDatabase.spec.defaultCypherLanguageis honoured on every create path, and gated on the server version. On CalVer, a database created with notopologyand noseedURIused to ignore the field and get the server default; it now gets the language you set. Existing databases keep theirs, because a database's language is fixed when it is created. On the 5.26 LTS,"25"now fails validation with a message naming the field (it used to fail atCREATE DATABASEwith a syntax error), and"5"is accepted and the clause left out, since every database there runs Cypher 5.Neo4jCompositeDatabasefollows the same rule.- A standalone ignores
Neo4jDatabase.spec.topology, as the docs always said: the operator no longer sends aTOPOLOGYclause to a standalone, andprimaries: 0there is a warning instead of an error. - Sizes are checked before they reach Kubernetes. A cluster and a standalone
now accept the same
spec.storage.size: any Kubernetes quantity greater than zero, so1.5Giworks on a cluster and0is refused on both. A malformed size (fifty,10 Gi, or5K, since a capital K is not a Kubernetes suffix) used to pass validation and crash the operator; the CR now goesFailedwith a message naming the field.Neo4jBackup.spec.storage.pvc.sizeis checked the same way. Every value that is newly refused either crashed the operator or could hold no data. - A dotted
Neo4jCompositeDatabase.spec.nameis refused when you apply. It always failed at reconcile; the schema now says so up front. - Auth provider names follow the Neo4j manual.
plugin-<name>, for an auth plugin or an add-on such as Kerberos, is now accepted inspec.auth.authenticationProvidersandauthorizationProviders; it used to be refused.oidcwithout a provider name,kerberos,jwt,samlandcustomare not values Neo4j documents: they still validate, and now raise aValidationWarningevent that names what to use instead. See Multi-provider support.
New warnings¶
A field the schema accepts but nothing in the operator acts on now raises a
ValidationWarning event when you set it: … is accepted but has no effect
today: <what to do instead>. The warnings never block a reconcile. They cover:
Neo4jPlugin:spec.resources,spec.source.registry(and itstls),spec.security.securityPolicy;- clusters and standalones:
spec.tls.certificateSecret; standalones only:spec.tls.strictPeerValidation: false; - clusters:
spec.topology.placement.nodeSelectorand.requiredDuringScheduling; Neo4jDatabase:spec.initialData.source(other thancypher),.configMapRef,.secretRefand.storage;Neo4jBackupandNeo4jRestorecloud storage:identity.serviceAccount, andidentity.autoCreate.enabled: false;AuraInstance:spec.connectionSecretFormat: custom.
Metrics¶
Removed: twelve families that were registered but that no code ever
recorded. Each was a vector with no observations, so none ever exported a
series and no dashboard or alert loses data; you can delete panels built on
them. neo4j_operator_ followed by: backup_size_bytes,
cypher_execution_duration_seconds, cypher_executions_total,
disaster_recovery_status, failover_total, replication_lag_seconds,
manual_scaler_enabled, primary_count, secondary_count,
scale_events_total, scaling_validation_total, security_operations_total.
New or now populated:
neo4j_operator_replica_lag_transactionsandneo4j_operator_replica_promotions_totalfor cross-cluster replication (see Cross-cluster replication metrics). The lag series is removed when it can no longer be trusted (the replica is gone or promoted, or its lag cannot be read) instead of holding its last value.neo4j_operator_upgrade_duration_secondsis now recorded, once per ended rolling-upgrade phase.
New, no action needed¶
status.upgradeStatus.phaseStartTimeon clusters.Neo4jShardedDatabasestatus now fillscreationTime,graphShard,propertyShardsandvirtualDatabase;Neo4jPluginstatus fillsinstalledVersionandinstallationTime. They were in the schema but empty.ConnectivityDegraded(a Warning on the cluster) now needs ten consecutive connectivity failures spanning at least five minutes, not ten alone. A new cluster no longer raises it while it forms; if you alert on this event, expect it no earlier than five minutes into a real outage.- A failed Aura Fleet Management token registration raises an
AuraFleetManagementFailedWarning event, once per distinct failure message. It almost never fired before.
Upgrading from v1.18.x¶
Apply the new CRDs with the operator. They add three spec fields —
Neo4jRestore.spec.source.sourceDatabase,
Neo4jBackup.spec.options.splitArchivePartSize and
Neo4jEnterpriseStandalone.spec.podServiceAccountAnnotations — and status
fields the operator now records: Neo4jBackup status.history[].artifactType
(with databaseArtifacts[].type and shardArtifacts[].type), and Neo4jRestore
status.resolvedSource.artifactType and backupStartedAt. Without the new
CRDs those status fields are dropped on write; restores still work, merging
the chain of every PVC artifact they cannot tell is a full backup. The
behaviour changes below take effect on the first reconcile.
Behaviour changes¶
- A cluster that loses a server stays
Ready. It used to drop toFormingon any one pod restart, which paused everyNeo4jUser,Neo4jRole,Neo4jDatabase,Neo4jBackupand the rest until the server came back, and left a cluster whose server never came backFormingfor good. A cluster that has formed now staysReadywhile a majority of its servers is serving, with a newDegradedcondition naming the missing servers. If a server is still missing after the grace period (5 minutes;--server-unavailable-grace, HelmserverUnavailableGrace), the phase turnsDegraded:status.readyisfalse, theReadycondition isFalsewith reasonClusterDegraded, and aClusterDegradedWarning event is raised. Losing a majority still reportsForming, now with aClusterQuorumLostWarning. See Server availability. - Dependents keep working against a
Degradedcluster. Users, roles, bindings, auth rules, databases, sharded databases, aliases, composites, replicas, promotions and backups reconcile as they do against aReadyone. A rolling image upgrade or aNeo4jPlugininstall waits until every server is back, including during the grace period. - Alerts and pipelines:
kubectl wait --for=condition=Ready, Flux health checks and the ArgoCD health checks report aDegradedcluster as not ready — that is new, since it used to beForming(Ready=Unknown, ArgoCDProgressing). If you alert onneo4j_operator_cluster_phase{phase="Forming"}to catch a lost server, alert onphase="Degraded"too, or on theDegradedcondition directly. - Diagnostics keep running while a server is down.
ServersHealthy,DatabasesHealthy,status.diagnosticsandneo4j_operator_server_healthused to freeze at their last healthy values whenever the cluster was notReady; they are now collected whenever the cluster has formed. ClusterFormationStartedis raised on first formation only, no longer on every pod restart of a formed cluster.neo4j_operator_server_healthno longer leaves series behind. A server that was down was reported withserver_address="<nil>"(also instatus.diagnostics.servers[].address), which started a new series and left the old one exported at its last value — a0that kept aserver_health == 0alert firing after the server came back. A down server now keeps the last address it reported, and series a cluster no longer reports are withdrawn.- A standalone restores online. A
Neo4jRestoreinto aNeo4jEnterpriseStandaloneno longer stops the instance: it runsdbms.recreateDatabase/CREATE DATABASE … OPTIONS { seedURI }against it, so only the restored database is unavailable, andstopCluster: trueis ignored. These still restore offline and needstopCluster: true:source.type: storage; a point-in-time restore that cannot run online (below); cloud storage by pod identity, unless the standalone sets the newspec.podServiceAccountAnnotations(below); and a backup run that recorded no artifact. A restore already running offline when you upgrade finishes offline. See Restore to a Standalone Instance. - From cloud storage with static credentials, the standalone's own pods
now fetch the seed. They need the credentials Secret in
spec.extraEnvFrom(and, for MinIO, the endpoint inspec.env), or theneo4j.com/auto-inherit-seed-creds: "true"annotation, which adds them at the cost of one restart. Without either, the restore fails and says so. - Point-in-time restores run online. A
Neo4jRestorewithsource.pointInTimefrom aNeo4jBackupin cloud storage, into a database that does not exist yet, on CalVer, now creates the database withseedRestoreUntil, on a cluster or a standalone. It used to stop a standalone for the Job, and a cluster refused it. The restore now uses the backup run that holds the point in time (the earliest that started at or after it), not the most recent run. Other point-in-time restores still take the Job on a standalone; on a cluster they fail naming the reason. See Point-in-Time Recovery. - Cluster restores run their hooks.
spec.options.preRestoreandpostRestorewere ignored on clusters; they now run before the restore is issued and once the database is online, as on a standalone. A failing post-restore hook fails the restore. Check any clusterNeo4jRestorethat carries hooks before re-running it. - PVC differentials restore online. Seeding a cluster from a PVC
differential — every scheduled
backupType: AUTOrun after the first — created the database and left it offline ("not part of a valid backup chain"). The seed proxy now merges the chain into one full backup first, with the target's own Neo4j image, unless the backup recorded the artifact as a full backup. The merge needs scratch space about the size of the chain (anemptyDirunless you setspec.options.tempStorage) and time: the restore waits up tospec.timeout, 30 minutes by default while merging. Sharded databases are the exception (next two items). - A sharded seed from a PVC differential fails at once. A sharded
database seeds from a PVC only when every shard of the run is a full
backup, and a differential cannot be merged into one. A
seedBackupRefwhose latest run holds a differential shard used to fail inside Neo4j after the seed proxy started; it now fails at once, naming the shards, and seeds once a full run lands. An all-databases PVC run that writes a differential shard raises aBackupShardedDifferentialwarning. backupType: AUTOtakes full backups of a sharded database on a PVC. ANeo4jBackupwithspec.shardedDatabaseand PVC storage used to write a differential on every run after the first, and none of those can seed a sharded database.AUTO(the default) now takes a full backup on every run there. Expect each run to be as large as the first; size the PVC andspec.retentionfor it. Cloud storage keepsAUTOas it was, since it seeds differentials. See Restoring a sharded database.- A plugin no longer overrides a standalone's own procedure settings.
On a
Neo4jEnterpriseStandalone, aNeo4jPluginalso wrote its security settings (dbms.security.procedures.*and the like) as environment variables, which Neo4j applies overneo4j.conf— so a standalone's ownspec.configvalues for those keys were silently replaced by the plugin's (for examplegds.*,apoc.*cut toapoc.*). They now live only inneo4j.conf, merged with yours, and the plugin'sspec.securityis written there too. Each standalone with aNeo4jPluginrestarts once on upgrade as the environment copies are removed. Clusters are unchanged. - A deleted cluster stops exporting metrics. Its series —
cluster_healthy,cluster_phase,server_healthand the rest — stayed exported at their last values until the operator restarted; they are now removed when the cluster is deleted. kubectl neo4j validate --connectchecks namespace-less manifests in the right namespace. Without-nit looked cross-references up in an empty namespace and reported raw client errors (and could pass a remote composite whose target has no keystore); it now uses the kubeconfig context's namespace, elsedefault.- A finished one-time backup stays finished. A
Neo4jBackupwithout a schedule that wasCompletedorFailedturnedWaitingwhenever its target restarted or was briefly missing, and once its Job had been cleaned up it could run again, writing a new backup. It now keeps its phase. backupType: DIFFis refused for a sharded database. Neo4j does not back up property shards differentially, so every run of such a backup failed. ANeo4jBackupwithspec.shardedDatabaseandbackupType: DIFFis now refused by validation and names the field; useAUTOorFULL.- A sharded seed from MinIO gets its endpoint. Seeding a sharded database
from S3-compatible storage under
neo4j.com/auto-inherit-seed-credsadded only the credentials to the cluster, so Neo4j went to AWS for the bucket. The operator now adds the endpoint too, in the same rolling restart, and waits for it before seeding.
New, no action needed¶
Neo4jEnterpriseStandalone.spec.podServiceAccountAnnotationsbinds a standalone's pod to a cloud role (Workload Identity), as the cluster field does: the operator creates a<name>-neo4jServiceAccount carrying them and runs the pod under it, so a restore from cloud storage without a credentials Secret runs online. Standalones that do not set it are not restarted by the upgrade. Apply the new CRDs to use it.Neo4jBackupstatus.history[].artifactType(anddatabaseArtifacts[].type):FULLorDIFF, read from each run's log.Neo4jRestorestatus.resolvedSource.artifactTypecarries it into the restore.- An all-databases restore records
status.completionTime. Neo4jRestorestatus.resolvedSource.backupStartedAt: when the resolved backup run started.- A standalone restores into a new database name. It used to look for the
target name's files and fail. Standalone restores from a
backupRefnow read the run's recorded artifact, as cluster restores always have. NewNeo4jRestore.spec.source.sourceDatabasepicks one database out of an all-databases backup to restore underspec.database, on clusters and standalones. See Restoring under a different name. Neo4jBackup.spec.options.splitArchivePartSize(Neo4j 2026.09+) writes each artifact as several files — see Split backup archives. Apply the new CRDs to use it. PVC retention now deletes a split artifact's data parts with it; before, passing--split-archive-part-sizethroughadditionalArgsleft the parts on the volume.- Conditions
DegradedandClusterFormedonNeo4jEnterpriseCluster. - The
Readycondition of aDegradedcluster has reasonClusterDegradedinstead ofReconciliationFailed. - Operator flag
--server-unavailable-grace(default5m) and Helm valueserverUnavailableGrace.
Upgrading from v1.19.x¶
Apply the new CRDs with the operator. They add spec.monitoring.logs to
Neo4jEnterpriseCluster and Neo4jEnterpriseStandalone, and change the
description of spec.topology.minSystemPrimaries. Upgrading the operator
restarts no server. The new startup-script blocks it adds take effect at each server's
next restart, and the operator does not restart servers for them. The
behaviour changes below take effect on the first reconcile.
Behaviour changes¶
- A new cluster of more than three servers has three
systemprimaries. Each server's role for thesystemdatabase is now fixed at its first start: servers belowspec.topology.minSystemPrimaries(defaultmin(3, servers)) are primaries, the rest secondaries. Before, every server was a primary.system(databases, users, roles) stays writable while a majority of its primaries is up — with the default, two of servers 0–2, however large the cluster. SetminSystemPrimariesto an odd number above 3 if you need more. Servers that already exist keep their role. See System primaries and secondaries. - Scaling up restarts nothing, as long as every added server is a system
secondary (with the default, any scale-up from three servers or more); a
ScaledWithoutRestartevent says so. A scale-up that adds a system primary, such as 2 → 3, still restarts the servers. Scaling down restarts nothing. - Changing a setting Neo4j can change at runtime restarts nothing. When a
spec.configchange touches only dynamic settings, the operator applies it to every running server (dbms.setConfigValue) and then writes it toneo4j.conf, raisingConfigAppliedLive. Anything else restarts the servers as before, andConfigNeedsRestartnames the setting and the reason. A change to comments or blank lines in the rendered configuration restarts nothing either. See Which changes restart the servers. - 5.26 clusters stop stalling writes while a server is down. On
5.26.29 and later the operator enables
dbms.cluster.raft.async_channel_acquisition_enabled, which stops the leader waiting up to 30 seconds for a stopped member. Existing servers get it at their next restart; until then the newRestartPendingcondition names them. See 5.26: writes while a server is stopped. - Renewed TLS certificates are reloaded without a restart with
spec.tls.mode: cert-manageron CalVer 2025.03 and later. The operator enablesdbms.security.tls_reload_enabledand reloads each renewal, raisingTLSCertificateReloaded. Existing servers get the setting at their next restart (RestartPendingnames them on a cluster); until then a renewal reaches them only when they restart, and aTLSCertificateNeedsRestartWarning names them. On 5.26 a renewal still takes effect at the next restart. See TLS certificate rotation. - Deleting a TLS deployment deletes its certificate Secret. cert-manager
leaves the Secrets it issues behind, so
{name}-tls-secret(a certificate and private key) outlived every deleted cluster and standalone. The operator now deletes it when cert-manager issued it for that deployment's Certificate; a Secret of that name you created yourself is kept. - A Ready cluster reconciles twice a minute, not continuously. Each pass
wrote a fresh
status.diagnostics.lastCollected, which re-queued the cluster at once. Diagnostics are now written when they change, or at least every 5 minutes, solastCollectedcan be up to 5 minutes old on a healthy cluster; alert on the conditions (ServersHealthy,DatabasesHealthy), not on its age. The standalone is the same. - Split-brain detection is paced on a quiet cluster. The full check,
which connects to every server, runs on a
Readycluster at most every 5 minutes while no server pod changes, and at once when one is deleted, recreated, restarts or changes readiness, or when a server is missing fromSHOW SERVERS.--split-brain-check-interval=0schecks on every pass, as before. See Many large clusters. - A crashed server container no longer turns the cluster
Forming. When Neo4j cannot be queried at all — the check landed on a container that had just died — a formed cluster with a majority of its server pods Ready now keeps its phase. If it stays unreachable for the grace period (a wrong admin password, say) it turnsFormingas before. Neo4jDatabasenames must be 3 to 63 characters, as Neo4j requires. A name outside that range used to pass validation and fail atCREATE DATABASE; it is now refused by validation, naming the rule.- A scale-down no longer raises a false
ScaleDownBlocked. A drain step Neo4j had already taken ("already deallocating", "already dropped") was reported as a blocked scale-down while it went on to complete.
New, no action needed¶
spec.monitoring.logs.stdout(clusters and standalones) writes Neo4j'squery,securityanddebuglogs to standard output as JSON, besides their files, for an OpenTelemetry Collector or another node-level log collector. Turning it on restarts each server once; deployments that do not set it are unchanged. See OpenTelemetry, which includes a tested Collector configuration for these logs and Neo4j's metrics. Apply the new CRDs to use it.- Operator flags
--ready-poll-interval(default30s) and--split-brain-check-interval(default5m); Helm valuesreadyPollIntervalandsplitBrainCheckInterval. - Condition
RestartPendingonNeo4jEnterpriseCluster. - Events
ConfigAppliedLive,ConfigNeedsRestart,ScaledWithoutRestart,TLSCertificateReloadedandTLSCertificateNeedsRestart. - Annotations the operator records:
neo4j.com/deferred-settingsandneo4j.com/deferred-settings-sinceon the cluster ConfigMap,neo4j.com/tls-certificateon the StatefulSet of a TLS deployment, andneo4j.com/config-semantic-hashon the standalone's StatefulSet. Each cluster server records itssystemrole in/data/.neo4j-operator/system-database-mode.
Upgrading from v1.21.0¶
No CRD changes; upgrading the operator restarts no server.
Fixes¶
- A backup-mode
Neo4jReplicaDatabasefindsAWS_REGIONinspec.extraEnvFrom. The region check before seeding froms3://read onlyspec.envand the server container'senv, so a downstream cluster whose region came from a Secret or ConfigMap inspec.extraEnvFrom— the field is documented for exactly that — had its replicaFailedwith "AWS_REGION is not set". A replica in that state is retried once the upgraded operator runs.kubectl neo4j preflightreads the same sources. - A plugin's
NEO4J_PLUGINScould vanish from a cluster's StatefulSet. When the cluster controller's StatefulSet update conflicted with the plugin controller's patch, the retry applied the template it had just read and recorded the plugin's variables as its own; the next pass removed them. TheNeo4jPluginstayedReadywith the plugin missing from the servers. The upgraded operator reconciles everyNeo4jPluginwhen it starts, which puts a missingNEO4J_PLUGINSback — rolling that cluster's servers once, as the original install did. - Advisory warnings are announced once, not on every reconcile.
ValidationWarningevents — and a cluster'sTopologyWarning— were emitted again on every pass, dozens a minute for one object, which also used up that object's event budget so other events could be dropped. Each warning is now announced when it starts to apply and again every 30 minutes while it still does, so it stays visible inkubectl describewithout the flood.
Upgrading from v1.20.x¶
Behaviour changes¶
- A rolling upgrade waits for each restarted server's databases. Before
the next server restarts, every database copy on the one that just did must
have caught up (
dbms.cluster.statusCheck, andSHOW DATABASESfor single-primary databases and secondaries);status.upgradeStatus.messagenames the databases it is waiting for. A server used to count as done once it rejoined, while its databases could still be catching up, and restarting the next one then left a database with three primaries a single working copy. Upgrades of clusters with many databases take somewhat longer — about 15 seconds per server with 30 databases on a laptop — and stay withinupgradeTimeout. spec.upgradeStrategy.maxUnavailableDuringUpgradeset to anything other than1raises aValidationWarning. It never had an effect: servers restart one at a time, as Neo4j's rolling upgrade requires. Remove it, or leave it at1.- Diagnostics keep updating during a rolling upgrade.
status.diagnostics, theServersHealthyandDatabasesHealthyconditions and theneo4j_operator_server_healthmetric used to keep their values from before the upgrade until it finished; they now follow the servers as they restart, at most once per--ready-poll-interval. Alerts on them should allow for a server being down for a minute or so, as the documented examples (5 minutes) do. - The operator reuses its Neo4j connections. It used to open new ones, and
log in, on every pass: about 17
logged inlines a minute insecurity.logfor one quiet 3-server cluster, now under one. A changed admin password or TLS certificate still takes effect at the next pass. - The
<cluster>-discoveryRole, RoleBinding and Service are deleted. The Role and RoleBinding let the server pods list Services and Endpoints; the Service exposed the V1 discovery port 5000. Nothing used them: discovery reads pod addresses from DNS. Upgrading the operator deletes the ones it created and restarts nothing; the<cluster>-discoveryServiceAccount stays, with anyspec.podServiceAccountAnnotations. An object of that name that the operator did not create is left alone. The operator's own ClusterRole now only reads and deletes Roles and RoleBindings. - A failed cluster reconcile is retried on its own backoff (5–30 seconds). Retries used to share one slot every 6 seconds across all clusters, so after a failure that hit many clusters at once some waited minutes.
- Clusters get
dbms.cluster.network.connect_timeout=5s(Neo4j's default is 30s). Upgrading the operator applies it to the running servers without a restart (aConfigAppliedLiveevent); Neo4j's Raft connections take it up at each server's next restart. It removes pauses of about 10 seconds on a database whose leadership moved to a server that had just restarted. To keep 30s, set it inspec.config. See Writes while a restarted server rejoins. - Clusters are reconciled four at a time instead of one, and each
cluster's reconcile is cut off and retried after 10 minutes. One slow or
unreachable cluster no longer delays the others. The new flags
--cluster-max-concurrent-reconcilesand--cluster-reconcile-timeout(HelmclusterMaxConcurrentReconciles,clusterReconcileTimeout) change them;--cluster-max-concurrent-reconciles=1restores the old behaviour. See Many large clusters.
Upgrading between future releases¶
When a newer version ships:
- Refresh the CRDs first. Helm does not upgrade CRDs automatically, so a new field or validation won't take effect until the CRDs are applied. Apply the bundle for the version you are upgrading to (replace the tag):
kubectl apply --server-side -f \
https://github.com/priyolahiri/neo4j-kubernetes-operator/releases/download/v1.21.1/neo4j-kubernetes-operator.yaml
- Upgrade the operator via Helm:
helm repo update
helm upgrade neo4j-operator neo4j-operator/neo4j-operator \
--namespace neo4j-operator-system
(or re-apply the complete bundle if you installed with plain kubectl —
see the Installation guide).
- Read the release notes for that version for any breaking changes or manual steps, and roll forward one minor version at a time if you are skipping several.
The operator reconciles declaratively, so once the new version is running it
converges existing Neo4j* resources to the new behaviour automatically.