
:guide-id: update-compatibility
:guide-parent: 
:guide-title: Checking if rolling updates are possible
:guide-summary: Execute the update compatibility command to check if {project_name} supports a rolling update for a change in your deployment.
:guide-priority: 999
:guide-tile-visible: true
:version: 26.4.0

include::../attributes.adoc[]

[[update-compatibility]]
= Checking if rolling updates are possible

ifeval::["" == "true"]
WARNING: This {section} is describing a feature which is currently in preview.
ifeval::["" == ""]
Please provide your feedback while we’re continuing to work on this.
endif::[]
ifeval::["" != ""]
Please provide your feedback by link:[joining this discussion] while we’re continuing to work on this.
endif::[]
endif::[]


Use the update compatibility command to determine if you can update your deployment with a rolling update strategy when enabling or disabling features or changing the {project_name} version, configurations or providers and themes.
The outcome shows whether a rolling update is possible or if a recreate update is required.

In its current version, it shows that a rolling update is possible when the {project_name} version is the same for the old and the new version.
Future versions of {project_name} might change that behavior to use additional information from the configuration, the image and the version to determine if a rolling update is possible.

[NOTE]
====
In the next iteration of this feature, it is possible to use rolling update strategy also when updating to the following patch release of {project_name}.
Refer to <<rolling-updates-for-patch-releases>> section for more details.
====

This is fully scriptable, so your update procedure can use that information to perform a rolling or recreate strategy depending on the change performed.
It is also GitOps friendly, as it allows storing the metadata of the previous configuration in a file. Use  this file in a CI/CD pipeline with the new configuration to determine if a rolling update is possible or if a recreate update is needed.

If you are using the {project_name} Operator, continue to the link:{links_operator_rolling-updates_url}[{links_operator_rolling-updates_name}] {section} and the `Auto` strategy for more information.

== Supported update strategies

Rolling Update::
In this guide, a rolling update is an update that can be performed with zero downtime for your deployment, which consists of at least two nodes.
Update your {project_name} one by one; shut down one of your old deployment nodes and start a new deployment node.
Wait until the new node's start-up probe returns success before proceeding to the next {project_name} node. See {section} link:{links_observability_health_url}[{links_observability_health_name}] for details on how to enable and use the start-up probe.

Recreate Update::
A recreate update is not compatible with zero-downtime and requires downtime to be applied.
Shut down all nodes of the cluster running the old version before starting the nodes with the new version.

== Determining the update strategy for an updated configuration

To determine if a rolling update is possible:

1. Run the update compatibility command to generate the required metadata with the old configuration.
2. Check the metadata with the new configuration to determine the update strategy.

NOTE: If you do not use `--optimized` keep in mind that an `update` command may implicitly create or update an optimized build for you - if you are running the command from the same machine as a server instance, this may impact the next start of your server.

[WARNING]
====
Consumers of these commands should not rely on the internal behavior or the structure of the metadata file.
Instead, they should rely only on the exit code of the `check` command to benefit from future enhancements on the internal logic to determine when a rolling update is possible.
====

=== Generating the Metadata

To generate the metadata, execute the following command using the same {project_name} version and configuration options:

.Generate and save the metadata from the current deployment.
[source,bash]
----
bin/kc.[sh|bat] update-compatibility metadata --file=/path/to/file.json
----

This command accepts all options used by the `start` command.
The command displays the metadata, in JSON format, in the console for debugging purposes.
The `--file` parameter allows you to save the metadata to a file.
Use this file with the subsequent `check` command.

[WARNING]
====
Ensure that all configuration options, whether set via environment variables or CLI arguments, are included when running the above command.

Omitting any configuration options results in incomplete metadata, and could lead to a wrong reported result in the next step.
====

=== Checking the Metadata

This command checks the metadata generated by the previous command and compares it with the current configuration and {project_name} version.
If you are updating to a new {project_name} version, this command must be executed with the new version.

.Check the metadata from a previous deployment.
[source,bash]
----
bin/kc.[sh|bat] update-compatibility check --file=/path/to/file.json
----

[WARNING]
====
* Ensure that all configuration options, whether set via environment variables or CLI arguments, are included when running this command.

* Verify that the correct {project_name} version is used.

Failure to meet these requirements results in an incorrect outcome.
====

The command prints the result to the console.
For example, if a rolling update is possible, it displays:

.Rolling Update possible message
[source,bash]
----
[OK] Rolling Update is available.
----

If no rolling update is possible, the command provides details about the incompatibility:

.Rolling Update not possible message
[source,bash]
----
[keycloak] Rolling Update is not available. 'keycloak.version' is incompatible: 26.2.0 -> 26.2.1 #<1>
----
<1> In this example, the Keycloak version `26.2.0` is not compatible with version `26.2.1` and a rolling update is not possible.

[NOTE]
====
In the next iteration of this feature, it is possible to use rolling update strategy also when updating to the following patch release of {project_name}.
Refer to <<rolling-updates-for-patch-releases>> section for more details.
====

*Command exit code*

Use the command's exit code to determine the update type in your automation pipeline:

|===
|Exit Code |Description

m|0
|Rolling Update is possible.

m|1
|Unexpected error occurred (such as the metadata file is missing or corrupted).

m|2
|Invalid CLI option.

m|3
|Rolling Update is not possible.
The deployment must be shut down before applying the new configuration.

m|4
|Rolling Update is not possible.
The feature `rolling-updates` is disabled.
|===

== Rolling incompatible changes

The following configuration changes return a "Rolling Update is not possible" result code.

=== Features

==== Recreate always

The enabling or disabling of the following features requires a recreate update:

[cols="30%,70%"]
|===
| Feature | Description

| [.features-name]#multi-site:v1# | [.features-description]#Multi-site support#
| [.features-name]#persistent-user-sessions:v1# | [.features-description]#Persistent online user sessions across restarts and upgrades#
|===


==== Recreate on feature version change

Changing the following features versions triggers a recreate update:

[cols="30%,70%"]
|===
| Feature | Description

| [.features-name]#login:v1# | [.features-description]#Legacy Login Theme#
| [.features-name]#login:v2# | [.features-description]#New Login Theme#
| [.features-name]#passkeys-conditional-ui-authenticator:v1# | [.features-description]#Passkeys conditional UI authenticator#
|===

=== Configuration options

Changing the value of one of the following CLI options triggers a recreate update:

[caption=]
.Cache
[cols="30%,70%", options="header"]
|===
| Option                          | Rationale
| `--cache`                       | The `ispn` and `local` configurations are mutually exclusive, changing from one to another will lead to data loss.
| `--cache-config-file`           | Changing the configuration file could result in incompatible cache or transport configurations, resulting in clusters not forming as expected.
| `--cache-stack`                 | Changing stack will result in the cluster not forming during rolling update and will lead to data loss.
| `--cache-embedded-mtls-enabled` | Enabling/Disabling TLS will result in the cluster not forming during rolling update and will lead to data loss.
| `--cache-remote-host`           | Connecting to a new remote cache will cause previously cached data to be lost.
| `--cache-remote-port`           | Connecting to a new remote cache will cause previously cached data to be lost.
|===

[WARNING]
====
{project_name} does not verify changes to the content of the cache configuration file provided via `--cache-config-file`.
If you change this file, you need to review and test your changes to ensure that nodes using the new configuration can form a cluster with the nodes running the old configuration.
If a cluster cannot be formed, you should shut down {project_name} running the old configuration first before migrating to the new configuration.
====

[caption=]
.Database
[cols="30%,70%", options="header"]
|===
| Option              | Rationale
| `--db`              | Migration to a new database vendor should be applied to all cluster members to ensure data consistency.
| `--db-schema`       | Migration to a new database schema should be applied to all cluster members to ensure data consistency.
| `--db-url-database` | Migration to a new database name should be applied to all cluster members to ensure data consistency.
| `--db-url-host`     | All cluster members should be connecting to the same database to ensure data consistency.
| `--db-url-port`     | All cluster members should be connecting to the same database to ensure data consistency.
|===

[WARNING]
====
{project_name} allows changes to the `--db-url` option to be rolled out in order to facilitate changes to JDBC properties.
Great care should be taken when updating this value as changes to the host, port or database name could lead to distinct
cluster members connecting to a different database, resulting in data consistency issues.
====

[[rolling-updates-for-patch-releases]]
== Rolling updates for patch releases

WARNING: This behavior is currently in preview mode, and it is not recommended for use in production.

It is possible to configure the {project_name} compatibility command to allow rolling updates when upgrading to a newer patch version in the same `+major.minor+` release stream.

To enable this behavior for compatibility check command enable feature `rolling-updates:v2` as shown in the following example.
[source,bash]
----
bin/kc.[sh|bat] update-compatibility check --file=/path/to/file.json --features=rolling-updates:v2
----

Note there is no change needed when generating metadata using `metadata` command.

Recommended Configuration:

* Enable sticky sessions in your loadbalancer to avoid users bouncing between different versions of {project_name} as this could result in users needing to refresh their Account Console and Admin UI multiple times while the upgrade is progressing.

Supported functionality during rolling updates:

* Users can log in and log out for OpenID Connect clients.

* OpenID Connect clients can perform all operations, for example, refreshing tokens and querying the user info endpoint.

Known limitations:

* If there have been changes to the Account Console or Admin UI in the patch release, and the user opened the Account Console or Admin UI before or during the upgrade, the user might see an error message and be asked to reload the application while navigating in browser during or after the upgrade.

* If the two patch releases of {project_name} use different versions of the embedded Infinispan, no rolling update of {project_name} be performed.

== Further reading

The {project_name} Operator uses the functionality described above to determine if a rolling update is possible. See the link:{links_operator_rolling-updates_url}[{links_operator_rolling-updates_name}] {section} and the `Auto` strategy for more information.


== Relevant options

[cols="12a,4",role="options"]
|===
| |Value

|
[.options-key]#`+features+`# [.none]#icon:tools[role=options-build]#

[.options-description]#Enables a set of one or more features.#

[role="options-extended"]
--




*CLI:* `+--features+` +
*Env:* `+KC_FEATURES+`
--



|
`+account-api[:v1]+`, `+account[:v3]+`, `+admin-api[:v1]+`, `+admin-fine-grained-authz[:v1,v2]+`, `+admin[:v2]+`, `+authorization[:v1]+`, `+ciba[:v1]+`, `+client-auth-federated[:v1]+`, `+client-policies[:v1]+`, `+client-secret-rotation[:v1]+`, `+client-types[:v1]+`, `+clusterless[:v1]+`, `+db-tidb[:v1]+`, `+declarative-ui[:v1]+`, `+device-flow[:v1]+`, `+docker[:v1]+`, `+dpop[:v1]+`, `+dynamic-scopes[:v1]+`, `+fips[:v1]+`, `+hostname[:v2]+`, `+impersonation[:v1]+`, `+instagram-broker[:v1]+`, `+ipa-tuura-federation[:v1]+`, `+kerberos[:v1]+`, `+kubernetes-service-accounts[:v1]+`, `+log-mdc[:v1]+`, `+login[:v2,v1]+`, `+logout-all-sessions[:v1]+`, `+multi-site[:v1]+`, `+oid4vc-vci[:v1]+`, `+opentelemetry[:v1]+`, `+organization[:v1]+`, `+par[:v1]+`, `+passkeys-conditional-ui-authenticator[:v1]+`, `+passkeys[:v1]+`, `+persistent-user-sessions[:v1]+`, `+preview+`, `+quick-theme[:v1]+`, `+recovery-codes[:v1]+`, `+rolling-updates[:v1,v2]+`, `+scripts[:v1]+`, `+spiffe[:v1]+`, `+step-up-authentication[:v1]+`, `+token-exchange-external-internal[:v2]+`, `+token-exchange-standard[:v2]+`, `+token-exchange[:v1]+`, `+transient-users[:v1]+`, `+update-email[:v1]+`, `+user-event-metrics[:v1]+`, `+web-authn[:v1]+`, `+workflows[:v1]+`

|
[.options-key]#`+features-disabled+`# [.none]#icon:tools[role=options-build]#

[.options-description]#Disables a set of one or more features.#

[role="options-extended"]
--




*CLI:* `+--features-disabled+` +
*Env:* `+KC_FEATURES_DISABLED+`
--



|
`+account+`, `+account-api+`, `+admin+`, `+admin-api+`, `+admin-fine-grained-authz+`, `+authorization+`, `+ciba+`, `+client-auth-federated+`, `+client-policies+`, `+client-secret-rotation+`, `+client-types+`, `+clusterless+`, `+db-tidb+`, `+declarative-ui+`, `+device-flow+`, `+docker+`, `+dpop+`, `+dynamic-scopes+`, `+fips+`, `+impersonation+`, `+instagram-broker+`, `+ipa-tuura-federation+`, `+kerberos+`, `+kubernetes-service-accounts+`, `+log-mdc+`, `+login+`, `+logout-all-sessions+`, `+multi-site+`, `+oid4vc-vci+`, `+opentelemetry+`, `+organization+`, `+par+`, `+passkeys+`, `+passkeys-conditional-ui-authenticator+`, `+persistent-user-sessions+`, `+preview+`, `+quick-theme+`, `+recovery-codes+`, `+rolling-updates+`, `+scripts+`, `+spiffe+`, `+step-up-authentication+`, `+token-exchange+`, `+token-exchange-external-internal+`, `+token-exchange-standard+`, `+transient-users+`, `+update-email+`, `+user-event-metrics+`, `+web-authn+`, `+workflows+`


|===
