title: Write-behind configuration for mysql

title: application.properties

text: [code example]

code:
debezium.sink.type=redis
debezium.sink.redis.message.format=extended
debezium.sink.redis.address=<RDI_HOST>:<RDI_PORT>
# Comment the following line if not using a password for Write-behind.
debezium.sink.redis.password=<RDI_PASSWORD>
debezium.sink.redis.memory.limit.mb=80
# Redis SSL/TLS
#debezium.sink.redis.ssl.enabled=true
# When Redis is configured with a replica shard, these properties allow to verify that the data has been written to the replica.
#debezium.sink.redis.wait.enabled=true
#debezium.sink.redis.wait.timeout.ms=1000
#debezium.sink.redis.wait.retry.enabled=true
#debezium.sink.redis.wait.retry.delay.ms=1000
#debezium.source.database.history.redis.ssl.enabled=true
# Location of the Java keystore file containing an application process' own certificate and private key.
#javax.net.ssl.keyStore=<KEY_STORE_FILE_PATH>
# Password to access the private key from the keystore file specified by javax.net.ssl.keyStore. This password is used twice: To unlock the keystore file (store password), and To decrypt the private key stored in the keystore (key password).
#javax.net.ssl.keyStorePassword=<KEY_STORE_PASSWORD>
# Location of the Java keystore file containing the collection of CA certificates trusted by this application process (trust store).
#javax.net.ssl.trustStore=<TRUSE_STORE_FILE_PATH>
# Password to unlock the keystore file (store password) specified by javax.net.ssl.trustStore.
#javax.net.ssl.trustStorePassword=<TRUST_STORE_PASSWORD>

debezium.source.connector.class=io.debezium.connector.mysql.MySqlConnector
# A numeric ID of this database client, which must be unique across all currently-running database processes in the MySQL cluster.
debezium.source.database.server.id=1
debezium.source.offset.storage=io.debezium.storage.redis.offset.RedisOffsetBackingStore
debezium.source.topic.prefix=<SOURCE_LOGICAL_SERVER_NAME>

debezium.source.database.hostname=<SOURCE_DB_HOST>
debezium.source.database.port=<SOURCE_DB_PORT>
debezium.source.database.user=<SOURCE_DB_USER>
debezium.source.database.password=<SOURCE_DB_PASSWORD>
debezium.source.include.schema.changes=false
# Determines whether the connector should omit publishing change events when there are no modifications in the included columns.
debezium.source.skip.messages.without.change=true
debezium.source.offset.flush.interval.ms=1000
debezium.source.tombstones.on.delete=false
debezium.source.schema.history.internal=io.debezium.storage.redis.history.RedisSchemaHistory

# Important: Do NOT use `include` and `exclude` database lists at the same time, use either `include` or `exclude`.
# An optional, comma-separated list of regular expressions that match database names to be monitored.
# By default, all databases are monitored.
#debezium.source.database.include.list=<DB_NAME1>,<DB_NAME2>...
# An optional, comma-separated list of regular expressions that match database names for which you do not want to capture changes.
#debezium.source.database.exclude.list=<DB_NAME1>,<DB_NAME2>...
# Important: Do NOT use `include` and `exclude` table lists at the same time, use either `include` or `exclude`.
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers of tables whose changes you want to capture.
#debezium.source.table.include.list=<DB_NAME.TABLE_NAME1>,<DB_NAME.TABLE_NAME2>...
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers for tables whose changes you do not want to capture.
#debezium.source.table.exclude.list=<DB_NAME.TABLE_NAME1>,<DB_NAME.TABLE_NAME2>...

# Important: Do NOT use include and exclude column lists at the same time, use either include or exclude.
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to include in change event record values.
#debezium.source.column.include.list=<DB_NAME.TABLE_NAME.COLUMN_NAME1>,<DB_NAME.TABLE_NAME.COLUMN_NAME2>...
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to exclude from change event record values.
#debezium.source.column.exclude.list=<DB_NAME.TABLE_NAME.COLUMN_NAME1>,<DB_NAME.TABLE_NAME.COLUMN_NAME2>...

# Records only DDL statements that are relevant to tables whose changes are being captured by Debezium.
# In case of changing the captured tables, run `redis-di reset`.
debezium.source.schema.history.internal.store.only.captured.tables.ddl=true

# Whether to include the detailed schema information generated by Debezium in each record written to RDI.
# Note: Including the schema reduces the initial sync throughput and is not recommended for large data sets.
debezium.source.key.converter.schemas.enable=false
debezium.source.value.converter.schemas.enable=false
# When detailed schema information is excluded, handle decimal numeric types as strings.
debezium.source.decimal.handling.mode=string

debezium.transforms=AddPrefix
debezium.transforms.AddPrefix.type=org.apache.kafka.connect.transforms.RegexRouter
debezium.transforms.AddPrefix.regex=.*
debezium.transforms.AddPrefix.replacement=data:$0

# Logging
# Uncomment the following lines if running Debezium Server as a Java standalone process (non-containerized).
#quarkus.log.file.enable=true
#quarkus.log.file.path=<LOG_FILE_PATH>
#quarkus.log.file.rotation.max-file-size=100M
#quarkus.log.file.rotation.rotate-on-boot=true
#quarkus.log.file.rotation.file-suffix=.yyyy-MM-dd.gz
#quarkus.log.file.rotation.max-backup-index=3

# The default minimum log level for every log category, change only quarkus.log.level when needed.
quarkus.log.min-level=TRACE
# The default log level for every log category.
quarkus.log.level=INFO
# Determine whether to enable the JSON console formatting extension, which disables "normal" console formatting.
quarkus.log.console.json=false
# The port on which Debezium exposes Microprofile Health endpoint and other exposed status information.
quarkus.http.port=8088


title: Write-behind configuration for oracle

summary: Describes the `application.properties` settings that configure Debezium Server for oracle

page_type: content

title: application.properties

role: overview

text: [code example]

code:
debezium.sink.type=redis
debezium.sink.redis.message.format=extended
debezium.sink.redis.address=<RDI_HOST>:<RDI_PORT>
# Comment the following line if not using a password for Write-behind.
debezium.sink.redis.password=<RDI_PASSWORD>
debezium.sink.redis.memory.limit.mb=80
# Redis SSL/TLS
#debezium.sink.redis.ssl.enabled=true
# When Redis is configured with a replica shard, these properties allow to verify that the data has been written to the replica.
#debezium.sink.redis.wait.enabled=true
#debezium.sink.redis.wait.timeout.ms=1000
#debezium.sink.redis.wait.retry.enabled=true
#debezium.sink.redis.wait.retry.delay.ms=1000
#debezium.source.database.history.redis.ssl.enabled=true
# Location of the Java keystore file containing an application process' own certificate and private key.
#javax.net.ssl.keyStore=<KEY_STORE_FILE_PATH>
# Password to access the private key from the keystore file specified by javax.net.ssl.keyStore. This password is used twice: To unlock the keystore file (store password), and To decrypt the private key stored in the keystore (key password).
#javax.net.ssl.keyStorePassword=<KEY_STORE_PASSWORD>
# Location of the Java keystore file containing the collection of CA certificates trusted by this application process (trust store).
#javax.net.ssl.trustStore=<TRUSE_STORE_FILE_PATH>
# Password to unlock the keystore file (store password) specified by javax.net.ssl.trustStore.
#javax.net.ssl.trustStorePassword=<TRUST_STORE_PASSWORD>

debezium.source.connector.class=io.debezium.connector.oracle.OracleConnector
debezium.source.log.mining.strategy=online_catalog
debezium.source.log.mining.transaction.retention.ms=180000
# This mode creates a JDBC query that filters not only operation types at the database level, but also schema, table, and username include/exclude lists.
debezium.source.log.mining.query.filter.mode=in
# The name of the Oracle Pluggable Database that the connector captures changes from.
# For non-CDB installation, do not specify this property.
#debezium.source.database.pdb.name=ORCLPDB1
# Enables capturing and serialization of large object (CLOB, NCLOB, and BLOB) column values in change events.
#debezium.source.lob.enabled=true
# Specifies the constant that the connector provides to indicate that the original value is unchanged and not provided by the database.
#debezium.source.unavailable.value.placeholder=__debezium_unavailable_value
debezium.source.offset.storage=io.debezium.storage.redis.offset.RedisOffsetBackingStore
debezium.source.topic.prefix=<SOURCE_LOGICAL_SERVER_NAME>
debezium.source.database.dbname=<SOURCE_DB_NAME>

debezium.source.database.hostname=<SOURCE_DB_HOST>
debezium.source.database.port=<SOURCE_DB_PORT>
debezium.source.database.user=<SOURCE_DB_USER>
debezium.source.database.password=<SOURCE_DB_PASSWORD>
debezium.source.include.schema.changes=false
# Determines whether the connector should omit publishing change events when there are no modifications in the included columns.
debezium.source.skip.messages.without.change=true
debezium.source.offset.flush.interval.ms=1000
debezium.source.tombstones.on.delete=false
debezium.source.schema.history.internal=io.debezium.storage.redis.history.RedisSchemaHistory

# Important: Do NOT use `include` and `exclude` table lists at the same time, use either `include` or `exclude`.
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers of tables whose changes you want to capture.
#debezium.source.table.include.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers for tables whose changes you do not want to capture.
#debezium.source.table.exclude.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...

# Important: Do NOT use include and exclude column lists at the same time, use either include or exclude.
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to include in change event record values.
#debezium.source.column.include.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to exclude from change event record values.
#debezium.source.column.exclude.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...

# Records only DDL statements that are relevant to tables whose changes are being captured by Debezium.
# In case of changing the captured tables, run `redis-di reset`.
debezium.source.schema.history.internal.store.only.captured.tables.ddl=true

# Whether to include the detailed schema information generated by Debezium in each record written to RDI.
# Note: Including the schema reduces the initial sync throughput and is not recommended for large data sets.
debezium.source.key.converter.schemas.enable=false
debezium.source.value.converter.schemas.enable=false
# When detailed schema information is excluded, handle decimal numeric types as strings.
debezium.source.decimal.handling.mode=string

debezium.transforms=AddPrefix
debezium.transforms.AddPrefix.type=org.apache.kafka.connect.transforms.RegexRouter
debezium.transforms.AddPrefix.regex=.*
debezium.transforms.AddPrefix.replacement=data:$0

# Logging
# Uncomment the following lines if running Debezium Server as a Java standalone process (non-containerized).
#quarkus.log.file.enable=true
#quarkus.log.file.path=<LOG_FILE_PATH>
#quarkus.log.file.rotation.max-file-size=100M
#quarkus.log.file.rotation.rotate-on-boot=true
#quarkus.log.file.rotation.file-suffix=.yyyy-MM-dd.gz
#quarkus.log.file.rotation.max-backup-index=3

# The default minimum log level for every log category, change only quarkus.log.level when needed.
quarkus.log.min-level=TRACE
# The default log level for every log category.
quarkus.log.level=INFO
# Determine whether to enable the JSON console formatting extension, which disables "normal" console formatting.
quarkus.log.console.json=false
# The port on which Debezium exposes Microprofile Health endpoint and other exposed status information.
quarkus.http.port=8088

section_id: application-properties


title: Write-behind configuration for postgresql

summary: Describes the `application.properties` settings that configure Debezium Server for postgresql

title: application.properties

text: [code example]

code:
debezium.sink.type=redis
debezium.sink.redis.message.format=extended
debezium.sink.redis.address=<RDI_HOST>:<RDI_PORT>
# Comment the following line if not using a password for Write-behind.
debezium.sink.redis.password=<RDI_PASSWORD>
debezium.sink.redis.memory.limit.mb=80
# Redis SSL/TLS
#debezium.sink.redis.ssl.enabled=true
# When Redis is configured with a replica shard, these properties allow to verify that the data has been written to the replica.
#debezium.sink.redis.wait.enabled=true
#debezium.sink.redis.wait.timeout.ms=1000
#debezium.sink.redis.wait.retry.enabled=true
#debezium.sink.redis.wait.retry.delay.ms=1000
#debezium.source.database.history.redis.ssl.enabled=true
# Location of the Java keystore file containing an application process' own certificate and private key.
#javax.net.ssl.keyStore=<KEY_STORE_FILE_PATH>
# Password to access the private key from the keystore file specified by javax.net.ssl.keyStore. This password is used twice: To unlock the keystore file (store password), and To decrypt the private key stored in the keystore (key password).
#javax.net.ssl.keyStorePassword=<KEY_STORE_PASSWORD>
# Location of the Java keystore file containing the collection of CA certificates trusted by this application process (trust store).
#javax.net.ssl.trustStore=<TRUSE_STORE_FILE_PATH>
# Password to unlock the keystore file (store password) specified by javax.net.ssl.trustStore.
#javax.net.ssl.trustStorePassword=<TRUST_STORE_PASSWORD>

debezium.source.connector.class=io.debezium.connector.postgresql.PostgresConnector
debezium.source.plugin.name=pgoutput
debezium.source.offset.storage=io.debezium.storage.redis.offset.RedisOffsetBackingStore
debezium.source.topic.prefix=<SOURCE_LOGICAL_SERVER_NAME>
debezium.source.database.dbname=<SOURCE_DB_NAME>

debezium.source.database.hostname=<SOURCE_DB_HOST>
debezium.source.database.port=<SOURCE_DB_PORT>
debezium.source.database.user=<SOURCE_DB_USER>
debezium.source.database.password=<SOURCE_DB_PASSWORD>
debezium.source.include.schema.changes=false
# Determines whether the connector should omit publishing change events when there are no modifications in the included columns.
# This property takes effect when the `REPLICA IDENTITY` of the table is set to `FULL`.
debezium.source.skip.messages.without.change=true
debezium.source.offset.flush.interval.ms=1000
debezium.source.tombstones.on.delete=false
debezium.source.schema.history.internal=io.debezium.storage.redis.history.RedisSchemaHistory

# Important: Do NOT use `include` and `exclude` table lists at the same time, use either `include` or `exclude`.
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers of tables whose changes you want to capture.
#debezium.source.table.include.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers for tables whose changes you do not want to capture.
#debezium.source.table.exclude.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...

# Important: Do NOT use include and exclude column lists at the same time, use either include or exclude.
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to include in change event record values.
#debezium.source.column.include.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to exclude from change event record values.
#debezium.source.column.exclude.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...

# Whether to include the detailed schema information generated by Debezium in each record written to RDI.
# Note: Including the schema reduces the initial sync throughput and is not recommended for large data sets.
debezium.source.key.converter.schemas.enable=false
debezium.source.value.converter.schemas.enable=false
# When detailed schema information is excluded, handle decimal numeric types as strings.
debezium.source.decimal.handling.mode=string

debezium.transforms=AddPrefix
debezium.transforms.AddPrefix.type=org.apache.kafka.connect.transforms.RegexRouter
debezium.transforms.AddPrefix.regex=.*
debezium.transforms.AddPrefix.replacement=data:$0

# Logging
# Uncomment the following lines if running Debezium Server as a Java standalone process (non-containerized).
#quarkus.log.file.enable=true
#quarkus.log.file.path=<LOG_FILE_PATH>
#quarkus.log.file.rotation.max-file-size=100M
#quarkus.log.file.rotation.rotate-on-boot=true
#quarkus.log.file.rotation.file-suffix=.yyyy-MM-dd.gz
#quarkus.log.file.rotation.max-backup-index=3

# The default minimum log level for every log category, change only quarkus.log.level when needed.
quarkus.log.min-level=TRACE
# The default log level for every log category.
quarkus.log.level=INFO
# Determine whether to enable the JSON console formatting extension, which disables "normal" console formatting.
quarkus.log.console.json=false
# The port on which Debezium exposes Microprofile Health endpoint and other exposed status information.
quarkus.http.port=8088


title: Write-behind configuration for sqlserver

summary: Describes the `application.properties` settings that configure Debezium Server for sqlserver

title: application.properties

text: [code example]

code:
debezium.sink.type=redis
debezium.sink.redis.message.format=extended
debezium.sink.redis.address=<RDI_HOST>:<RDI_PORT>
# Comment the following line if not using a password for Write-behind.
debezium.sink.redis.password=<RDI_PASSWORD>
debezium.sink.redis.memory.limit.mb=80
# Redis SSL/TLS
#debezium.sink.redis.ssl.enabled=true
# When Redis is configured with a replica shard, these properties allow to verify that the data has been written to the replica.
#debezium.sink.redis.wait.enabled=true
#debezium.sink.redis.wait.timeout.ms=1000
#debezium.sink.redis.wait.retry.enabled=true
#debezium.sink.redis.wait.retry.delay.ms=1000
#debezium.source.database.history.redis.ssl.enabled=true
# Location of the Java keystore file containing an application process' own certificate and private key.
#javax.net.ssl.keyStore=<KEY_STORE_FILE_PATH>
# Password to access the private key from the keystore file specified by javax.net.ssl.keyStore. This password is used twice: To unlock the keystore file (store password), and To decrypt the private key stored in the keystore (key password).
#javax.net.ssl.keyStorePassword=<KEY_STORE_PASSWORD>
# Location of the Java keystore file containing the collection of CA certificates trusted by this application process (trust store).
#javax.net.ssl.trustStore=<TRUSE_STORE_FILE_PATH>
# Password to unlock the keystore file (store password) specified by javax.net.ssl.trustStore.
#javax.net.ssl.trustStorePassword=<TRUST_STORE_PASSWORD>

debezium.source.connector.class=io.debezium.connector.sqlserver.SqlServerConnector
debezium.source.database.names=<SOURCE_DB_NAME>
debezium.source.database.encrypt=false
debezium.source.offset.storage=io.debezium.storage.redis.offset.RedisOffsetBackingStore
debezium.source.topic.prefix=<SOURCE_LOGICAL_SERVER_NAME>

debezium.source.database.hostname=<SOURCE_DB_HOST>
debezium.source.database.port=<SOURCE_DB_PORT>
debezium.source.database.user=<SOURCE_DB_USER>
debezium.source.database.password=<SOURCE_DB_PASSWORD>
debezium.source.include.schema.changes=false
# Determines whether the connector should omit publishing change events when there are no modifications in the included columns.
debezium.source.skip.messages.without.change=true
debezium.source.offset.flush.interval.ms=1000
debezium.source.tombstones.on.delete=false
debezium.source.schema.history.internal=io.debezium.storage.redis.history.RedisSchemaHistory

# Important: Do NOT use `include` and `exclude` table lists at the same time, use either `include` or `exclude`.
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers of tables whose changes you want to capture.
#debezium.source.table.include.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...
# An optional, comma-separated list of regular expressions that match fully-qualified table identifiers for tables whose changes you do not want to capture.
#debezium.source.table.exclude.list=<SCHEMA_NAME.TABLE_NAME1>,<SCHEMA_NAME.TABLE_NAME2>...

# Important: Do NOT use include and exclude column lists at the same time, use either include or exclude.
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to include in change event record values.
#debezium.source.column.include.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...
# An optional, comma-separated list of regular expressions that match the fully-qualified names of columns to exclude from change event record values.
#debezium.source.column.exclude.list=<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME1>,<SCHEMA_NAME.TABLE_NAME.COLUMN_NAME2>...

# Whether to include the detailed schema information generated by Debezium in each record written to RDI.
# Note: Including the schema reduces the initial sync throughput and is not recommended for large data sets.
debezium.source.key.converter.schemas.enable=false
debezium.source.value.converter.schemas.enable=false
# When detailed schema information is excluded, handle decimal numeric types as strings.
debezium.source.decimal.handling.mode=string

debezium.transforms=AddPrefix
debezium.transforms.AddPrefix.type=org.apache.kafka.connect.transforms.RegexRouter
debezium.transforms.AddPrefix.regex=.*
debezium.transforms.AddPrefix.replacement=data:$0

# Logging
# Uncomment the following lines if running Debezium Server as a Java standalone process (non-containerized).
#quarkus.log.file.enable=true
#quarkus.log.file.path=<LOG_FILE_PATH>
#quarkus.log.file.rotation.max-file-size=100M
#quarkus.log.file.rotation.rotate-on-boot=true
#quarkus.log.file.rotation.file-suffix=.yyyy-MM-dd.gz
#quarkus.log.file.rotation.max-backup-index=3

# The default minimum log level for every log category, change only quarkus.log.level when needed.
quarkus.log.min-level=TRACE
# The default log level for every log category.
quarkus.log.level=INFO
# Determine whether to enable the JSON console formatting extension, which disables "normal" console formatting.
quarkus.log.console.json=false
# The port on which Debezium exposes Microprofile Health endpoint and other exposed status information.
quarkus.http.port=8088


title: Write-behind reference

summary: Collects reference material for Write-behind

summary: Write-behind CLI reference

title: CLI

summary: Data type conversion reference

title: Data type conversion

summary: Write-behind configuration file reference

title: Write-behind configuration file

summary: Data transformation block type reference

title: Data transformation block types

summary: JMESPath custom function reference

title: JMESPath custom functions

summary: Application properties settings used to configure Debezim Server for source database servers

title: Debezium Server configuration file

page_type: index


title: JMESPath custom functions

summary: JMESPath custom function reference

title: Content

role: content

text:
| Function             | Description                                                                                | Example                                                                                | Comments                                                                                |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `base64_decode`      | Decodes a base64(RFC 4648) encoded string                                                                                | Input: `{"encoded": "SGVsbG8gV29ybGQh"}`
 Expression: `base64_decode(encoded)`
 Output: `Hello World!`                                                                                |                                                                                |
| `capitalize`         | Capitalizes all the words in the string                                                                                | Input: `{"name": "john doe"}`
 Expression: `capitalize(name)`
 Output: `John Doe`                                                                                |                                                                                |
| `concat`             | Concatenates an array of variables or literals                                                                                | Input: `{"fname": "john", "lname": "doe"}`
 Expression: `concat([fname, ' ' ,lname])`
 Output: `john doe`                                                                                | This is equivalent to the more verbose built-in expression: `' '.join([fname,lname])`                                                                            |
| `filter_entries`     | Filters entries in a dictionary (object) using the given JMESPath predicate                                                         | Input: `{ "name": "John", "age": 30, "country": "US", "score": 15}`
 Expression: `` filter_entries(@, `key == 'name' \|\| key == 'age'`)``
 Output:`{"name": "John", "age": 30 }`             |                                                                                |
| `from_entries`       | Converts an array of objects with `key` and `value` properties into a single object                                                 | Input: `[{"key": "name", "value": "John"}, {"key": "age", "value": 30}, {"key": "city", "value": null}]`
 Expression: `from_entries(@)`
 Output: `{"name": "John", "age": 30, "city": null}` |                                                                                |
| `hash`               | Calculates a hash using the `hash_name` hash function and returns its hexadecimal representation                                    | Input: `{"some_str": "some_value"}`
 Expression: `hash(some_str, `sha1`)`
 Output: `8c818171573b03feeae08b0b4ffeb6999e3afc05`                                                        | Supported algorithms: sha1 (default), sha256, md5, sha384, sha3_384, blake2b, sha512, sha3_224, sha224, sha3_256, sha3_512, blake2s                              |
| `in`                 | Checks if an element matches any value in a list of values                                                                          | Input: `{"el": "b"}`
 Expression: `in(el, `["a", "b", "c"]`)`
 Output: `True`                                                                                |                                                                                |
| `left`               | Returns a specified number of characters from the start of a given text string                                                      | Input: `{"greeting": "hello world!"}`
 Expression: `left(greeting, `5`)`
 Output: `hello`                                                                                |                                                                                |
| `lower`              | Converts all uppercase characters in a string into lowercase characters                                                             | Input: `{"fname": "John"}`
 Expression: `lower(fname)`
 Output: `john`                                                                                |                                                                                |
| `mid`                | Returns a specified number of characters from the middle of a given text string                                                     | Input: `{"greeting": "hello world!"}`
 Expression: `mid(greeting, `4`, `3`)`
 Output: `o w`                                                                                |                                                                                |
| `json_parse`         | Returns parsed object from the given json string                                                                                | Input: `{"data": '{"greeting": "hello world!"}'}`
 Expression: `parse_json(data)`
 Output: `{"greeting": "hello world!"}`                                                                    |                                                                                |
| `regex_replace`      | Replaces a string that matches a regular expression                                                                                | Input: `{"text": "Banana Bannnana"}`
 Expression: `regex_replace(text, 'Ban\w+', 'Apple Apple')`
 Output: `Apple Apple`                                                                      |                                                                                |
| `replace`            | Replaces all the occurrences of a substring with a new one                                                                          | Input: `{"sentence": "one four three four!"}`
 Expression: `replace(sentence, 'four', 'two')`
 Output: `one two three two!`                                                                  |                                                                                |
| `right`              | Returns a specified number of characters from the end of a given text string                                                        | Input: `{"greeting": "hello world!"}`
 Expression: `right(greeting, `6`)`
 Output: `world!`                                                                                |                                                                                |
| `split`              | Splits a string into a list of strings after breaking the given string by the specified delimiter (comma by default)                | Input: `{"departments": "finance,hr,r&d"}`
 Expression: `split(departments)`
 Output: `['finance', 'hr', 'r&d']`                                                                             | Default delimiter is comma - a different delimiter can be passed to the function as the second argument, for example: `split(departments, ';')`                  |
| `time_delta_days`    | Returns the number of days between a given `dt` and now (positive) or the number of days that have passed from now (negative)       | Input: `{"dt": '2021-10-06T18:56:16.701670+00:00'}`
 Expression: `time_delta_days(dt)`
 Output: `365`                                                                                | If `dt` is a string, ISO datetime (2011-11-04T00:05:23+04:00, for example) is assumed. If `dt` is a number, Unix timestamp (1320365123, for example) is assumed. |
| `time_delta_seconds` | Returns the number of seconds between a given `dt` and now (positive) or the number of seconds that have passed from now (negative) | Input: `{"dt": '2021-10-06T18:56:16.701670+00:00'}`
 Expression: `time_delta_days(dt)`
 Output: `31557600`                                                                                | If `dt` is a string, ISO datetime (2011-11-04T00:05:23+04:00, for example) is assumed. If `dt` is a number, Unix timestamp (1320365123, for example) is assumed. |
| `to_entries`         | Converts a given object into an array of objects with `key` and `value` properties                                                  | Input: `{"name": "John", "age": 30, "city": null}`
 Expression: `to_entries(@)`
 Output: `[{"key": "name", "value": "John"}, {"key": "age", "value": 30}, {"key": "city", "value": null}]`   |                                                                                |
| `upper`              | Converts all lowercase characters in a string into uppercase characters                                                             | Input: `{"fname": "john"}`
 Expression: `upper(fname)`
 Output: `JOHN`                                                                                |                                                                                |
| `uuid`               | Generates a random UUID4 and returns it as a string in standard format                                                              | Input: None
 Expression: `uuid()`
 Output: `3264b35c-ff5d-44a8-8bc7-9be409dac2b7`                                                                                |                                                                                |


title: Redis products

summary: Products, services, and tools to operate a Redis database.

summary: The self-managed, enterprise-grade version of Redis.

title: Redis Software

summary: The fastest way to set up Redis - a fully managed Redis database on major public cloud services.

title: Redis Cloud

summary: Deploy and manage Redis Enterprise on Kubernetes with the Redis Enterprise operator.

title: Redis Enterprise for Kubernetes

summary: Operate Redis Open Source. Redis 8 in Redis Open Source replaces Redis Stack.

title: Redis Open Source

summary: Install and manage Redis Insight

title: Redis Insight

summary: Keep Redis in sync with a primary database in near real time.

title: Redis Data Integration (RDI)

title: Overview

text:
|  Redis Cloud |  Redis Software |
|:-----------|:--------------|
|

 [Get started with Redis Cloud]()

 [Create a database]()

 [Connect to your database]()

 [Subscriptions]()

[REST API]()

 |

 [Install Redis Software]()

 [Set up a new cluster]()

 [Create a database]()

 [Connect to your database]()

[REST API]()

 |
|  **Redis Open Source** |  **Redis for Kubernetes** |
|

 [Install Redis 8 in Redis Open Source]()

 [Install Redis Stack]() (≤ 7.4)

 [Manage Redis]()

 |

 [Deploy Redis for Kubernetes]()

 [Architecture]()

 [API Reference]()

 |
|  **Redis Insight** |  **Redis Data Integration (RDI)** |
|

 [Install Redis Insight]()

 [Use Redis Insight]()

 [Download Redis Insight](https://redis.io/downloads/#insight)

 |

 [RDI overview]()

 [Install RDI]()

 [RDI pipelines]()

 |

title: Product features

title: High availability and durability

text:
<!-- | Feature | RC        | RS         | Open Source       | K8s          | -->
| | <nobr> Redis</nobr> Cloud | <nobr> Redis</nobr> Software | <nobr> Redis</nobr> Open Source | <nobr> Redis for</nobr> Kubernetes |
|:-----------|:--------------|:-----------|:--------------|:--------------|
| Clustering | [Clustering]() | [Clustering]() | [Scale with Redis Cluster]() | [Redis Enterprise clusters (REC)]() |
| Replication | [Replication]() | [Replication]() | [Replication]() | [Create replica databases]()|
| Active-Active geo-distribution | [Active-Active Redis]() | [Active-Active Redis]() |  | [Active-Active databases]() |
| Rolling upgrades | [Upgrade database version]() | [Upgrade Redis Software]() |  | [Upgrade Redis for K8s]() |
| Redis Flex/Auto tiering | [Create a Redis Flex database]() | [Redis Flex]() |  | [Redis Flex]() |
| Persistence | [Data persistence]() | [Persistence]() | [Persistence]() | [Persistence volumes]()|
| Recovery | Automatic | [Recover cluster]() | [Manual failover]() | [Cluster recovery]() |
| Backups | [Back up a database]() | [Schedule backups]() | [Persistence]() | [REDB spec.backup]() |

title: Logging and monitoring

text:
| | <nobr> Redis</nobr> Cloud | <nobr> Redis</nobr> Software | <nobr> Redis</nobr> Open Source | <nobr> Redis for</nobr> Kubernetes |
|:-----------|:--------------|:-----------|:--------------|:--------------|
| Monitoring | [Monitor performance]() | [Monitoring]() | [INFO](), [MONITOR](), and [LATENCY DOCTOR]()
[Analysis with Redis Insight]() | [Export metrics to Prometheus]() |
| Logging | [System logs]() | [Logging]() | `/var/log/redis/redis.log`
[SLOWLOG]()
[Keyspace notifications]() | [Logs]() |
| Alerts | [Alerts]() | [Alerts and events]() | [Pub/sub with Redis Sentinel]() | [REDB alertSettings]() |
| Support | [Contact support](https://redis.io/support/) | [Create support package]() |  | [Contact support](https://redis.io/support/) |

title: Security

role: security

text:
| | <nobr> Redis</nobr> Cloud | <nobr> Redis</nobr> Software | <nobr> Redis</nobr> Open Source | <nobr>

 Redis for</nobr> Kubernetes |
|:-----------|:--------------|:-----------|:--------------|:--------------|
| Transport Layer Security (TLS) | [TLS]() | [TLS]() | [TLS]() | [REDB tlsMode]() |
| Role-based access control (RBAC) | [Role-based access control]() | [Access control]() | [Access control list]() | [REC credentials]() |
| Lightweight Directory Access Protocol (LDAP) |  | [LDAP authentication]() |  | [Enable LDAP]() |
| Single sign-on (SSO) | [SAML SSO]() |  |  |  |
| Self-signed certificates |  | [Certificates]() | [Certificate configuration]() | [REC certificates]() |
| Internode encryption | [Encryption at rest]() | [Internode encryption]() |  | [Enable internode encryption]() |
| Auditing |  | [Audit events]() | [Keyspace notifications]() |  |


title: Create Active-Active databases with crdb-cli

summary: This section shows how to set up an Active-Active Redis Enterprise database on Kubernetes using the Redis Enterprise Software operator.

title: Overview

text:
Versions 6.4.2 and later support the Active-Active database controller. This controller allows you to create Redis Enterprise Active-Active databases (REAADB) and Redis Enterprise remote clusters (RERC) with custom resources. We recommend using the [REAADB method for creating Active-Active databases]().

On Kubernetes, Redis Enterprise [Active-Active]() databases provide read-and-write access to the same dataset from different Kubernetes clusters. For more general information about Active-Active, see the [Redis Enterprise Software docs]().

Creating an Active-Active database requires routing [network access]() between two Redis Enterprise clusters residing in different Kubernetes clusters. Without the proper access configured for each cluster, syncing between the databases instances will fail.

This process consists of:

1. Documenting values to be used in later steps. It's important these values are correct and consistent.
1. Editing the Redis Enterprise cluster (REC) spec file to include the `ActiveActive` section. This will be slightly different depending on the K8s distribution you are using.
1. Creating the database with the `crdb-cli` command. These values must match up with values in the REC resource spec.

title: Prerequisites

text:
Before creating Active-Active databases, you'll need admin access to two or more working Kubernetes clusters that each have:

- Routing for external access with an [ingress resources]() (or [route resources]() on OpenShift).
- A working [Redis Enterprise cluster (REC)]() with a unique name.
- Enough memory resources available for the database (see [hardware requirements]()).

 The `activeActive` field and the `ingressOrRouteSpec` field cannot coexist in the same REC. If you configured your ingress via the `ingressOrRouteSpec` field in the REC, create your Active-Active database with the RedisEnterpriseActiveActiveDatabase (REAADB) custom resource.

title: Document required parameters

text:
The most common mistake when setting up Active-Active databases is incorrect or inconsistent parameter values. The values listed in the resource file must match those used in the crdb-cli command.

- **Database name** `<db-name>`:
  - Description: Combined with ingress suffix to create the Active-Active database hostname
  - Format: string
  - Example value: `myaadb`
  - How you get it: you choose
  - The database name requirements are:
       - Maximum of 63 characters
       - Only letter, number, or hyphen (-) characters
       - Starts with a letter; ends with a letter or digit.
       - Database name is not case-sensitive

You'll need the following information for each participating Redis Enterprise cluster (REC):

You'll need to create DNS aliases to resolve your API hostname `<api-hostname>`,`<ingress-suffix>`, `<replication-hostname>` to the IP address for the ingress controller’s LoadBalancer (or routes in Openshift) for each database. To avoid entering multiple DNS records, you can use a wildcard in your alias (such as *.ijk.example.com).

- **REC hostname** `<rec-hostname>`:
  - Description: Hostname used to identify your Redis Enterprise cluster in the `crdb-cli` command. This MUST be different from other participating clusters.
  - Format: `<rec-name>.<namespace>.svc.cluster.local`
  - Example value: `rec01.ns01.svc.cluster.local`
  - How to get it: List all your Redis Enterprise clusters
      [code example]
- **API hostname** `<api-hostname>`:
  - Description: Hostname used to access the Redis Enterprise cluster API from outside the K8s cluster
  - Format: string
  - Example value: `api.ijk.example.com`
- **Ingress suffix** `<ingress-suffix>`:
  - Description: Combined with database name to create the Active-Active database hostname
  - Format: string
  - Example value: `-cluster.ijk.example.com`
- [**REC admin credentials**]() `<username> <password>`:
  - Description: Admin username and password for the REC stored in a secret
  - Format: string
  - Example value: username: `user@example.com`, password: `something`
  - How to get them:
    [code example]
- **Replication hostname** `<replication-hostname>`:
  - Description: Hostname used inside the ingress for the database
  - Format: `<db-name><ingress-suffix>`
  - Example value: `myaadb-cluster.ijk.example.com`
  - How to get it: Combine `<db-name>` and `<ingress-suffix`> values you documented above.
- **Replication endpoint** `<replication-endpoint>`:
  - Description: Endpoint used externally to contact the database
  - Format: `<db-name><ingress-suffix>:443`
  - Example value: `myaadb-cluster.ijk.example.com:443`
  - How to get it:`<replication-hostname>:443`

title: Add `activeActive` section to the REC resource file

text:
From inside your K8s cluster, edit your Redis Enterprise cluster (REC) resource to add the following to the `spec` section. Do this for each participating cluster.

 The operator uses the API hostname (`<api-hostname>`) to create an ingress to the Redis Enterprise cluster's API; this only happens once per cluster. Every time a new Active-Active database instance is created on this cluster, the operator creates a new ingress route to the database with the ingress suffix (`<ingress-suffix>`). The hostname for each new database will be in the format <nobr>`<db-name><ingress-suffix>`</nobr>.

title: Using ingress controller

text:
1. If your cluster uses an [ingress controller](), add the following to the `spec` section of your REC resource file.

  Nginx:

  [code example]

HAproxy:

  [code example]

2. After the changes are saved and applied, you can verify a new ingress was created for the API.

    [code example]

3. Verify you can access the API from outside the K8s cluster.

    [code example]

    If the API call fails, create a DNS alias that resolves your API hostname (`<api-hostname>`) to the IP address for the ingress controller's LoadBalancer.

4. Make sure you have DNS aliases for each database that resolve your API hostname `<api-hostname>`,`<ingress-suffix>`, `<replication-hostname>` to the IP address of the ingress controller’s LoadBalancer. To avoid entering multiple DNS records, you can use a wildcard in your alias (such as `*.ijk.example.com`).

#### If using Istio Gateway and VirtualService

No changes are required to the REC spec if you are using [Istio]() in place of an ingress controller. The `activeActive` section added above creates ingress resources. The two custom resources used to configure Istio (Gateway and VirtualService) replace the need for ingress resources.

These custom resources are not controlled by the operator and will need to be configured and maintained manually.

For each cluster, verify the VirtualService resource has two `- match:` blocks in the `tls` section. The hostname under `sniHosts:` should match your `<replication-hostname>`.

title: Using OpenShift routes

text:
1. Make sure your Redis Enterprise cluster (REC) has a different name (`<rec-name.namespace>`) than any other participating clusters. If not, you'll need to manually rename the REC or move it to a different namespace.
            You can check your new REC name with:
    [code example]

    If the rec name was modified, reapply [scc.yaml](https://github.com/RedisLabs/redis-enterprise-k8s-docs/blob/master/openshift/scc.yaml) to the namespace to reestablish security privileges.

    [code example]

    Releases before 6.4.2-6 use the earlier version of the SCC, named `redis-enterprise-scc`.

1. Make sure you have DNS aliases for each database that resolve your API hostname `<api-hostname>`,`<ingress-suffix>`, `<replication-hostname>` to the route IP address. To avoid entering multiple DNS records, you can use a wildcard in your alias (such as `*.ijk.example.com`).

1. If your cluster uses [OpenShift routes](), add the following to the `spec` section of your Redis Enterprise cluster (REC) resource file.

      [code example]

1. Make sure you have DNS aliases that resolve to the routes IP for both the API hostname (`<api-hostname>`) and the replication hostname (`<replication-hostname>`) for each database. To avoid entering each database individually, you can use a wildcard in your alias (such as `*.ijk.example.com`).

1. After the changes are saved and applied, you can see that a new route was created for the API.

    [code example]

title: Create an Active-Active database with `crdb-cli`

text:
The `crdb-cli` command can be run from any Redis Enterprise pod hosted on any participating K8s cluster. You'll need the values for the [required parameters]() for each Redis Enterprise cluster.

[code example]

To create a database that syncs between more than two instances, add additional `--instance` arguments.

See the [`crdb-cli` reference]() for more options.

title: Test your database

text:
The easiest way to test your Active-Active database is to set a key-value pair in one database and retrieve it from the other.

You can connect to your databases with the instructions in [Manage databases](). Set a test key with `SET foo bar` in the first database. If your Active-Active deployment is working properly, when connected to your second database, `GET foo` should output `bar`.

code: kubectl get rec

section_id: document-required-parameters

code:
kubectl get secret <rec-name> \
      -o jsonpath='{.data.username}' | base64 --decode
    kubectl get secret <rec-name> \
      -o jsonpath='{.data.password}' | base64 --decode

code:
activeActive:
    apiIngressUrl: <api-hostname>
    dbIngressSuffix: <ingress-suffix>
    ingressAnnotations:
       kubernetes.io/ingress.class: nginx
      nginx.ingress.kubernetes.io/backend-protocol: HTTPS
      nginx.ingress.kubernetes.io/ssl-passthrough: "true"
    method: ingress

section_id: using-ingress-controller

code:
activeActive:
    apiIngressUrl: <api-hostname>
    dbIngressSuffix: <ingress-suffix>
    ingressAnnotations:
      kubernetes.io/ingress.class: haproxy
       ingress.kubernetes.io/ssl-passthrough: "true"
    method: ingress

code:
$ kubectl get ingress
    NAME   HOSTS                            ADDRESS                                 PORTS   AGE
    rec01  api.abc.cde.example.com  225161f845b278-111450635.us.cloud.com   80      24h

code: curl -k -L -i -u <username>:<password> https://<api-hostname>/v1/cluster

code: oc get rec -o jsonpath='{.items[0].metadata.name}'

section_id: using-openshift-routes

code:
oc apply -f scc.yaml
    oc adm policy add-scc-to-group redis-enterprise-scc-v2  system:serviceaccounts:<namespace>

code:
activeActive:
        apiIngressUrl: <api-hostname>
        dbIngressSuffix: <ingress-suffix>
        method: openShiftRoute

code:
$ oc get route
    NAME    HOST/PORT                       PATH    SERVICES  PORT  TERMINATION   WILDCARD
    rec01   api-openshift.apps.abc.example.com rec01   api             passthrough   None

code:
crdb-cli crdb create \
  --name <db-name> \
  --memory-size <mem-size> \
  --encryption yes \
  --instance fqdn=<rec-hostname-01>,url=https://<api-hostname-01>,username=<username-01>,password=<password-01>,replication_endpoint=<replication-endpoint-01>,replication_tls_sni=<replication-hostname-01> \
  --instance fqdn=<rec-hostname-02>,url=https://<api-hostname-02>,username=<username-02>,password=<password-02>,replication_endpoint=<replication-endpoint-02>,replication_tls_sni=<replication-hostname-02>


title: Create Active-Active database (REAADB)

title: Prerequisites

text:
To create an Active-Active database, make sure you've completed all the following steps and have gathered the information listed below each step.

1. Configure the [admission controller and ValidatingWebhook]().
   These are installed and enabled by default on clusters created via the OpenShift OperatorHub.

2. Create two or more [RedisEnterpriseCluster (REC) custom resources]() with enough [memory resources]().
   * Name of each REC (`<rec-name>`)
   * Namespace for each REC (`<rec-namespace>`)

3. Configure the REC [`ingressOrRoutes` field]() and [create DNS records]().
   * REC API hostname (`api-<rec-name>-<rec-namespace>.<subdomain>`)
   * Database hostname suffix (`-db-<rec-name>-<rec-namespace>.<subdomain>`)

4. [Prepare participating clusters]()
   * RERC name (`<rerc-name`>)
   * RERC secret name (`redis-enterprise-<rerc-name>`)

For a list of example values used throughout this article, see the [Example values](#example-values) section.

title: Create RERC custom resources {#create-rerc}

text:
1. Create a `RedisEnterpriseRemoteCluster` (RERC) custom resource file for each participating Redis Enterprise cluster (REC).

Below are examples of RERC resources for two participating clusters. Substitute your own values to create your own resource.

Example RERC (`rerc-ohare`) for the REC named `rec-chicago` in the namespace `ns-illinois`:

Example RERC (`rerc-raegan`) for the REC named `rec-arlington` in the namespace `ns-virginia`:

For more details on RERC fields, see the [RERC API reference]().

2. Create a Redis Enterprise remote cluster from each RERC custom resource file.

[code example]

3. Check the status of your RERC. If `STATUS` is `Active` and `SPEC STATUS` is `Valid`, then your configurations are correct.

[code example]

The output should look similar to:

[code example]

In case of errors, review the RERC custom resource events and the Redis Enterprise operator logs.

title: Create the REAADB {#create-reaadb}

text:
1. Create a `RedisEnterpriseActiveActiveDatabase` (REAADB) custom resource file meeting the naming requirements and listing the names of the RERC custom resources created in the last step.

Naming requirements:
* less than 63 characters
* contains only lowercase letters, numbers, or hyphens
* starts with a letter
* ends with a letter or digit
* **must be unique across all participating clusters**

   The admission controller prevents duplicate database names when databases are created via the Kubernetes operator. Ensure database names are unique across all participating clusters to avoid service deletion and database unavailability.

Example REAADB named `reaadb-boeing` linked to the REC named `rec-chicago` with two participating clusters and a global database configuration with shard count set to 3:

Sharding is disabled on Active-Active databases created with a `shardCount` of 1. Sharding cannot be enabled after database creation.

For more details on RERC fields, see the [RERC API reference]().

2. Create a Redis Enterprise Active-Active database from the REAADB custom resource file.

[code example]

3. Check the status of your RERC. If `STATUS` is `Active` and `SPEC STATUS` is `Valid`, your configurations are correct.

[code example]

The output should look similar to:

[code example]

In case of errors, review the REAADB custom resource events and the Redis Enterprise operator logs.

title: Example values

role: example

text:
This article uses the example values listed below. You can also find them in the [YAML examples]() section.

Example cluster 1:

* REC name: `rec-chicago`
* REC namespace: `ns-illinois`
* RERC name: `rerc-ohare`
* RERC secret name: `redis-enterprise-rerc-ohare`
* API FQDN: `api-rec-chicago-ns-illinois.example.com`
* DB FQDN suffix: `-db-rec-chicago-ns-illinois.example.com`

Example cluster 2:

* REC name: `rec-arlington`
* REC namespace: `ns-virginia`
* RERC name: `rerc-raegan`
* RERC secret name: `redis-enterprise-rerc-reagan`
* API FQDN: `api-rec-arlington-ns-virginia.example.com`
* DB FQDN suffix: `-db-rec-arlington-ns-virginia.example.com`

code: kubectl create -f <rerc-file>

code: kubectl get rerc <rerc-name>

code:
kubectl get rerc rerc-ohare

NAME        STATUS   SPEC STATUS   LOCAL
rerc-ohare   Active   Valid         true

code: kubectl create -f <reaadb-file>

section_id: create-the-reaadb-create-reaadb

code: kubectl get reaadb <reaadb-name>

code:
kubectl get reaadb reaadb-boeing

NAME              STATUS   SPEC STATUS   LINKED REDBS   REPLICATION STATUS
reaadb-boeing     active   Valid                        up


title: Edit participating clusters for Active-Active database

summary: Steps to add or remove a participating cluster to an existing Active-Active database with Redis Enterprise for Kubernetes.

title: Overview

text: This feature is supported for general availability in releases 6.4.2-6 and later. Some of these features were available as a preview in 6.4.2-4 and 6.4.2-5. Please upgrade to 6.4.2-6 for the full set of general availability features and bug fixes. and later.

title: Add a participating cluster

text: Use the following steps to add a participating cluster to an existing Redis Enterprise Active-Active database (REAADB) for Kubernetes.

title: Prerequisites

text:
To prepare the Redis Enterprise cluster (REC) to participate in an Active-Active database, perform the following tasks from [Prepare participating clusters]():

- Make sure the cluster meets the hardware and naming requirements.
- Enable the Active-Active controllers.
- Configure external routing.
- Configure `ValidatingWebhookConfiguration`.

title: Collect REC credentials

text:
To communicate with other clusters, all participating clusters need access to the admin credentials for all other clusters.

1. Get the REC credentials secret for the new participating cluster.

    [code example]

    This example shows an admin credentials secret for an REC named `rec-boston`:

    [code example]

1. Create a secret for the new participating cluster named `redis-enterprise-<rerc>` and add the username and password.

    The example below shows a secret file for a remote cluster named `rerc-logan` .

    [code example]

1. Apply the file of collected secrets to every participating REC.

    [code example]

 If the admin credentials for any of the clusters change, update and reapply the file to all clusters.

title: Create RERC

text:
1. From one of the existing participating clusters, create a `RedisEnterpriseRemoteCluster` (RERC) custom resource for the new participating cluster.

    This example (rerc-logan) shows an RERC custom resource for an REC named `rec-boston` in the namespace `ns-massachusetts`.

    [code example]

1. Create the RERC custom resource.

    [code example]

1. Check the status of the newly created RERC custom resource.

    [code example]

    The output should look like this:

    [code example]

title: Edit REAADB spec

text:
1. Patch the REAADB spec to add the new RERC name to the `participatingClusters`, replacing `<reaadb-name>` and `<rerc-name>` with your own values.

    [code example]

1. View the REAADB `participatingClusters` status to verify the cluster was added.

    [code example]

    The output should look like this:

    [code example]

title: Remove a participating cluster

text:
1. On an existing participating cluster,remove the desired cluster from the `participatingCluster` section of the REAADB spec.

    [code example]

1. On each of the other participating clusters, verify the status is `active` and the spec status is `Valid` and the cluster was removed.

   [code example]

    The output should look like this:

    [code example]

1. On the removed participating cluster, list all REAADB resources on the cluster to verify they were deleted.

    [code example]

1. List the status of all the participating clusters.

[code example]

code: kubectl get secret -o yaml <rec-name>

section_id: collect-rec-credentials

code:
apiVersion: v1
    data:
      password: ABcdef12345
      username: GHij56789
    kind: Secret
    metadata:
      name: rec-boston
    type: Opaque

code:
apiVersion: v1
    data:
      password: ABcdef12345
      username: GHij56789
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-logan
    type: Opaque

code: kubectl apply -f <rec-secret-file>

code:
apiVersion: app.redislabs.com/v1alpha1
    kind: RedisEnterpriseRemoteCluster
    metadata:
      name: rerc-logan
    spec:
      recName: rec-boston
      recNamespace: ns-massachusetts
      apiFqdnUrl: test-example-api-rec-boston-ns-massachusetts.example.com
      dbFqdnSuffix: -example-cluster-rec-boston-ns-massachusetts.example.com
      secretName: redis-enterprise-rerc-logan

section_id: create-rerc

code: kubectl create -f <new-RERC-file>

code: kubectl get rerc <RERC-name>

code:
NAME        STATUS   SPEC STATUS   LOCAL
    rerc-logan   Active   Valid         true

code: kubectl patch reaadb <reaadb-name> < --type merge --patch '{"spec": {"participatingClusters": [{"name": "<rerc-name>"}]}}'

section_id: edit-reaadb-spec

code: kubectl get reaadb <reaadb-name> -o=jsonpath='{.status.participatingClusters}'

code: kubectl edit reaadb <reaadb-name>

section_id: remove-a-participating-cluster

code: kubectl get reaadb <reaadb-name> -o=jsonpath='{.status}'

code: kubectl get reaadb -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}'


title: Edit Redis Enterprise remote clusters

summary: Edit the configuration details of an existing RERC with Redis Enterprise for Kubernetes.

title: Overview

text:
This feature is supported for general availability in releases 6.4.2-6 and later. Some of these features were available as a preview in 6.4.2-4 and 6.4.2-5. Please upgrade to 6.4.2-6 for the full set of general availability features and bug fixes. and later.

Before a RedisEnterpriseCluster (REC) can participate in an Active-Active database, it needs an accompanying RedisEnterpriseRemoteCluster (RERC) custom resource. The RERC contains details allowing the REC to link to the RedisEnterpriseActiveActiveDatabase (REAADB). The RERC resource is listed in the REAADB resource to become a participating cluster for the Active-Active database.

The RERC controller periodically connects to the local REC endpoint via its external address, to ensure it’s setup correctly. For this to work, the external load balancer must support [NAT hairpinning](https://en.wikipedia.org/wiki/Network_address_translation#NAT_loopback). In some cloud environments, this may involve disabling IP preservation for the load balancer target groups.

For more details, see the [RERC API reference]().

title: Edit RERC

text:
Use the `kubectl patch rerc <rerc-name> --type merge --patch` command to patch the local RERC custom resource with your changes. For a full list of available fields, see the [RERC API reference]().

The following example edits the `dbFqdnSuffix` field for the RERC named `rerc-ohare`.

[code example]

title: Update RERC secret

text:
If the credentials are changed or updated for a REC participating cluster, you need to manually edit the RERC secret and apply it to all participating clusters.

1. On the local cluster, update the secret with new credentials and name it with the following convention:  `redis-enterprise-<rerc-name>`.

    A secret for a remote cluster named `rerc-ohare` would be similar to the following:

    [code example]

1. Apply the file.

    [code example]

1. Watch the RERC to verify the status is "Active" and the spec status is "Valid."

      [code example]

    The output should look like this:

      [code example]

    To troubleshoot invalid configurations, view the RERC custom resource events and the [Redis Enterprise operator logs]().

1. Verify the status of each REAADB using that RERC is "Active" and the spec status is "Valid."

    [code example]
    The output should look similar to:

      [code example]

    To troubleshoot invalid configurations, view the RERC custom resource events and the [Redis Enterprise operator logs]().

1. Repeat the above steps on all other participating clusters.

code:
kubectl patch rerc rerc-ohare --type merge --patch \
'{"spec":{"dbFqdnSuffix": "-example2-cluster-rec-chicago-ns-illinois.example.com"}}'

section_id: edit-rerc

code:
apiVersion: v1
    data:
      password: PHNvbWUgcGFzc3dvcmQ+
      username: PHNvbWUgdXNlcj4
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-ohare
    type: Opaque

section_id: update-rerc-secret

code: kubectl apply -f <secret-file>

code: kubectl get rerc <rerc-name>

code:
NAME        STATUS   SPEC STATUS   LOCAL
        rerc-ohare   Active   Valid         true

code: kubectl get reaadb reaadb-boeing

code:
NAME              STATUS   SPEC STATUS   LINKED REDBS   REPLICATION STATUS
      reaadb-boeing     active   Valid                        up


title: Set global database configurations

summary: The REAADB contains the field '.spec.globalConfigurations' and through this the database configurations are set.

title: Overview

text:
The Redis Enterprise Active-Active database (REAADB) custom resource contains the field `.spec.globalConfigurations`. This field sets configurations for the Active-Active database across all participating clusters, such as memory size, shard count, and the global database secrets.

The [REAADB API reference]() contains a full list of available fields.

title: Edit global configurations

text:
1. Edit or patch the REAADB custom resource with your global configuration changes.

    The example command below patches the REAADB named `reaadb-boeing` to set the global memory size to 200MB:

    [code example]

1. Verify the status is `active` and the spec status is `Valid`.

    This example shows the status for the `reaadb-boeing` database.

    [code example]

1. View the global configurations on each participating cluster to verify they are synced.

    [code example]

title: Edit global configuration secrets

text:
This section edits the secrets under the REAADB `.spec.globalConfigurations` section. For more information and all available fields, see the [REAADB API reference]().

1. On an existing participating cluster, generate a YAML file containing the database secret with the relevant data.

    This example shoes a secret named `my-db-secret` with the password `my-password` encoded in base 64.

    [code example]

1. Apply the secret file from the previous step, substituting your own value for `<db-secret-file>`.

    [code example]

1. Patch the REAADB custom resource to specify the database secret, substituting your own values for `<reaadb-name>` and `<secret-name>`.

    [code example]

1. Check the REAADB status for an `active` status and `Valid` spec status.

    [code example]

1. On each other participating cluster, check the secret status.

    [code example]

    The output should show the status as `Invalid`.

    [code example]

1. Sync the secret on each participating cluster.

    [code example]

1. Repeat the previous two steps on every participating cluster.

title: Configure role permissions

role: configuration

text:
You can configure role-based access control (RBAC) permissions for Active-Active databases using the `rolesPermissions` field in the REAADB `.spec.globalConfigurations` section. The role permissions configuration is propagated across all participating clusters, but the underlying roles and Redis ACLs must be manually created on each cluster.

You must manually create the specified roles and Redis ACLs on all participating clusters before configuring role permissions. The operator only propagates the role permissions configuration—it does not create the underlying roles and ACLs. If roles or ACLs are missing on any cluster, the operator will log errors and dispatch an Event associated with the REAADB object until they are manually created.

title: Prerequisites

text:
Before configuring role permissions:

1. Manually create the required roles and Redis ACLs on all participating clusters using the Redis Enterprise admin console or REST API.
2. Ensure role and ACL names match exactly across all clusters (names are case-sensitive).
3. Verify that roles and ACLs are properly configured on each cluster.

The operator does not automatically create or synchronize roles and ACLs across clusters. You are responsible for manually creating identical roles and ACLs on each participating cluster.

title: Add role permissions to REAADB

text:
1. Create or update your REAADB custom resource to include `rolesPermissions` in the global configurations.

    Example REAADB with role permissions:

    [code example]

    Replace `<role-name>` and `<acl-name>` with the exact names of your Redis Enterprise role and ACL.

2. Apply the REAADB custom resource:

    [code example]

    Alternatively, patch an existing REAADB to add role permissions:

    [code example]

3. After the REAADB is active and its replication status is "Up", verify role permissions are applied to the local database using the Redis Enterprise REST API. See [Database requests]() for details.

title: Troubleshooting role permissions

role: errors

text:
If you encounter issues with role permissions:

- **Missing role or ACL errors**: Manually create the specified roles and ACLs on all participating clusters with exact name matches. The operator cannot create these automatically.
- **Permission propagation failures**: Verify that the roles and ACLs are properly configured and accessible on each cluster. Remember that you must manually create identical roles and ACLs on every participating cluster.
- **Case sensitivity issues**: Verify that role and ACL names match exactly, including capitalization, across all clusters.

For more details on the `rolesPermissions` field structure, see the [REAADB API reference]().

code:
kubectl patch reaadb reaadb-boeing --type merge --patch \
    '{"spec": {"globalConfigurations": {"memorySize": "200mb"}}}'

section_id: edit-global-configurations

code:
kubectl get reaadb reaadb-boeing

    NAME             STATUS   SPEC STATUS   GLOBAL CONFIGURATIONS REDB   LINKED REDBS
    reaadb-boeing   active   Valid

code: kubectl get reaadb <reaadb-name> -o yaml

code:
apiVersion: v1
     data:
      password: bXktcGFzcw
    kind: Secret
    metadata:
      name: my-db-secret
    type: Opaque

section_id: edit-global-configuration-secrets

code: kubectl apply -f <db-secret-file>

code:
kubectl patch reaadb <reaadb-name> --type merge --patch \
    '{"spec": {"globalConfigurations": {"databaseSecretName": "secret-name"}}}'

code:
kubectl get reaadb <reaadb-name>

    NAME             STATUS   SPEC STATUS   GLOBAL CONFIGURATIONS REDB   LINKED REDBS
    reaadb-boeing   active   Valid

code: kubectl get reaadb <reaadb-name> -o=jsonpath='{.status.secretsStatus}'

my-db-secret

status: Invalid

code:
apiVersion: app.redislabs.com/v1alpha1
    kind: RedisEnterpriseActiveActiveDatabase
    metadata:
      name: reaadb-boeing
    spec:
      globalConfigurations:
        databaseSecretName: <my-secret>
        memorySize: 200MB
        shardCount: 3
        rolesPermissions:
          - role: <role-name>
            acl: <acl-name>
            type: redis-enterprise
      participatingClusters:
        - name: rerc-ohare
        - name: rerc-reagan

section_id: add-role-permissions-to-reaadb

code: kubectl apply -f <reaadb-file>

code:
kubectl patch reaadb <reaadb-name> --type merge --patch \
    '{"spec": {"globalConfigurations": {"rolesPermissions": [{"role": "<role-name>", "acl": "<acl-name>", "type": "redis-enterprise"}]}}}'


title: Set global database secret

summary: The REAADB contains the field '.spec.globalConfigurations' to set the global database secret.

title: Set global database secret

text:
One of the fields available for `globalConfigurations` is `databaseSecretName` which can point to a secret containing the database password. To set the database secret name and sync the data to all participating clusters, follow the steps below.

To edit other global configruations, see [global configuration]()

1. On an existing participating cluster, generate a YAML file containing the database secret with the database password.

  This example shoes a secret named `my-db-secret` with the password `my-password` encoded in base 64.

  [code example]

1. Apply the secret file from the previous step, substituting your own value for `<db-secret-file>`.

    [code example]

1. Patch the REAADB custom resource to specify the database secret, substituting your own values for `<reaadb-name>` and `<secret-name>`.

    [code example]

1. Check the REAADB status for an `active` status and `Valid` spec status.

    [code example]

1. On each other participating cluster, check the secret status.

    ``sh
    kubectl get reaadb <reaadb-name> -o=jsonpath='{.status.secretsStatus}'
    [code example]sh
    [{"name":"my-db-secret","status":"Invalid"}]
    [code example]sh
    kubectl apply -f <db-secret-file>
    ```

1. Repeat the previous two steps on every participating cluster.

code:
apiVersion: v1
  data:
    password: bXktcGFzcw
  kind: Secret
  metadata:
    name: my-db-secret
  type: Opaque

section_id: set-global-database-secret

code:
kubectl get reaadb <reaadb-name>

    NAME             STATUS   SPEC STATUS   GLOBAL CONFIGURATIONS REDB   LINKED REDBS
    example-aadb-1   active   Valid

code: The output should show the status as `Invalid`.

code: 1. Sync the secret on each participating cluster.


title: Active-Active databases

summary: Create and manage Active-Active Redis Enterprise databases across multiple Kubernetes clusters.

summary: Prepare your participating RECs to be part of an Active-Active database deployment.

title: Prepare participating clusters

title: Create Active-Active database (REAADB)

title: Set global database configurations

title: Set global database secret

title: Edit Redis Enterprise remote clusters

title: Overview

text:
Redis Enterprise [Active-Active]() databases on Kubernetes provide read and write access to the same dataset from different Kubernetes clusters. This enables globally distributed applications with local read and write access, automatic conflict resolution, and seamless failover capabilities.

Active-Active databases use multi-master replication to keep data synchronized across participating clusters, allowing applications to read and write data locally while maintaining global consistency.

title: Active-Active setup methods

text:
There are two methods for creating an Active-Active database with Redis Enterprise for Kubernetes:

- The `RedisEnterpriseActiveActiveDatabase` (REAADB) custom resource is available for versions 6.4.2 and later.
- The `crdb-cli` method is available for versions 6.4.2 or earlier.

We recommend creating new Active-Active databases using the RedisEnterpriseActiveActiveDatabase (REAADB) custom resource. This allows you to manage your Active-Active database with the operator and ensures you have the latest features and functionality.

title: Active-Active controller method

text:
Versions 6.4.2-6 or later fully support the Active-Active controller. Some of these features were available as a preview in 6.4.2-4 and 6.4.2-5. Please upgrade to 6.4.2-6 for the full set of general availability features and bug fixes.

This setup method includes the following steps:

1. Gather REC credentials and [prepare participating clusters]().
2. Create [`RedisEnterpriseRemoteCluster` (RERC)]() resources.
3. Create [`RedisEnterpriseActiveActiveDatabase` (REAADB)]() resource.

title: `crdb-cli` method

text:
For versions 6.4.2 or earlier, this Active-Active setup method includes the following steps:

1. Install and configure an ingress.
2. Gather configuration details.
3. Add the `ActiveActive` field to the REC spec.
4. Create the database with the `crdb-cli` tool.

title: Redis Enterprise Active-Active controller for Kubernetes

text:
These features are supported for general availability in releases 6.4.2-6 and later.

[Active-Active]() databases give you read-and-write access to Redis Enterprise clusters (REC) in different Kubernetes clusters or namespaces. Active-Active deployments managed by the Redis Enterprise operator require two additional custom resources: Redis Enterprise Active-Active database (REAADB) and Redis Enterprise remote cluster (RERC).

To create an Active-Active Redis Enterprise deployment for Kubernetes with these new features, first [prepare participating clusters]() then [create an Active-Active database]().

title: REAADB custom resource

text:
Redis Enterprise Active-Active database (REAADB) contains a link to the RERC for each participating cluster, and provides configuration and status to the management plane.

For a full list of fields and options, see the [REAADB API reference]().

For examples, see the [YAML examples]() section.

title: RERC custom resource

text:
Redis Enterprise remote cluster (RERC) custom resource contains configuration details for all the participating clusters.

For a full list of fields and options, see the [RERC API reference]().

For examples, see the [YAML examples]() section.

title: Limitations

role: limits

text:
* Existing Redis databases cannot be migrated to a REAADB. (DOC-3594)
* Admission is not blocking REAADB with `shardCount` which exceeds license quota. (RED-96301)
    Workaround: Fix the problems with the REAADB and reapply.
* The `<rec-name>/<rec-namespace>` value must be unique for each RERC resource. (RED-96302)
* Only global database options are supported, no support for specifying configuration per location.
* No support for migration from old (`crdb-cli`) Active-Active database method to new Active-Active controller.
* No support for REAADB with participating clusters co-located within the same Kubernetes cluster, except for a single designated local participating cluster.
* Active-Active databases cannot be configured as [Redis Flex]() deployments.

title: More info

text: For more general information about Active-Active, see the [Redis Enterprise Software docs]().


title: Prepare participating clusters

title: Prepare participating clusters

text:
Before you prepare your clusters to participate in an Active-Active database, make sure you've completed all the following steps and have gathered the information listed below each step.

1. Configure the [admission controller and ValidatingWebhook]().

2. Create two or more [RedisEnterpriseCluster (REC) custom resources]() with enough [memory resources]().
   * Name of each REC (`<rec-name>`)
   * Namespace for each REC (`<rec-namespace>`)

3. Configure the REC [`ingressOrRoutes` field]() and [create DNS records]().
   * REC API hostname (`api-<rec-name>-<rec-namespace>.<subdomain>`)
   * Database hostname suffix (`-db-<rec-name>-<rec-namespace>.<subdomain>`)

Next you'll [collect credentials](#collect-rec-credentials) for your participating clusters and create secrets for the RedisEnterprsieRemoteCluster (RERC) to use.

For a list of example values used throughout this article, see the [Example values](#example-values) section.

title: Collect REC credentials

text:
To communicate with other clusters, all participating clusters will need access to the admin credentials for all other clusters.

1. Create a file to hold the admin credentials for all participating RECs (such as `all-rec-secrets.yaml`).

1. Within that file, create a new secret for each participating cluster named `redis-enterprise-<rerc-name>`.

    The example below shows a file (`all-rec-secrets.yaml`) holding secrets for two participating clusters:

    [code example]

1. Get the REC credentials secret for each participating cluster.

    [code example]

    The admin credentials secret for an REC named `rec-chicago` would be similar to this:

    [code example]

    The `username` and `password` values should be base64 encoded, not plain text.

1. Add the username and password to the new secret for that REC and namespace.

    This example shows the collected secrets file (`all-rec-secrets.yaml`) for `rerc-ohare` (representing `rec-chicago` in namespace `ns-illinois`) and `rerc-reagan` (representing `rec-arlington` in namespace `ns-virginia`).

    [code example]

1. Apply the file of collected secrets to every participating REC.

    [code example]

   If the admin credentials for any of the clusters changes, the file will need to be updated and reapplied to all clusters.

title: Next steps

text: Now you are ready to [create your Redis Enterprise Active-Active database]().

title: Example values

text:
This article uses the example values listed below. They can also be found in the [YAML examples]() section.

Example cluster 1:

* REC name: `rec-chicago`
* REC namespace: `ns-illinois`
* RERC name: `rerc-ohare`
* RERC secret name: `redis-enterprise-rerc-ohare`
* API FQDN: `api-rec-chicago-ns-illinois.example.com`
* DB FQDN suffix: `-db-rec-chicago-ns-illinois.example.com`

Example cluster 2:

* REC name: `rec-arlington`
* REC namespace: `ns-virginia`
* RERC name: `rerc-raegan`
* RERC secret name: `redis-enterprise-rerc-reagan`
* API FQDN: `api-rec-arlington-ns-virginia.example.com`
* DB FQDN suffix: `-db-rec-arlington-ns-virginia.example.com`

code:
apiVersion: v1
    data:
      password:
      username:
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-ohare
    type: Opaque

    ---

    apiVersion: v1
    data:
      password:
      username:
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-reagan
    type: Opaque

code: kubectl get secret -o yaml <rec-name>

code:
apiVersion: v1
    data:
      password: ABcdef12345
      username: GHij56789
    kind: Secret
    metadata:
      name: rec-chicago
    type: Opaque

code:
apiVersion: v1
    data:
      password: ABcdef12345
      username: GHij56789
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-ohare
    type: Opaque

    ---

    apiVersion: v1
    data:
      password: KLmndo123456
      username: PQrst789010
    kind: Secret
    metadata:
      name: redis-enterprise-rerc-reagan
    type: Opaque

code: kubectl apply -f <all-rec-secrets-file>


title: Flexible deployment options

summary: Redis Enterprise for Kubernetes allows you to deploy to multiple namespaces. This article describes flexible deployment options you can use to meet your specific needs.

title: Overview

text:
You can deploy Redis Enterprise for Kubernetes in several different ways depending on your database needs.

Multiple RedisEnterpriseDatabase (REDB) resources can be associated with a single Redis Enterprise cluster resource (REC) even if they reside in different namespaces.

The Redis Enterprise cluster (REC) custom resource must reside in the same namespace as the Redis Enterprise operator.

 Multi-namespace installations don't support Active-Active databases (REEADB). Only databases created with the REDB resource are supported in multi-namespace deployments at this time.

title: Single REC and single namespace (one-to-one)

text: The standard and simplest deployment deploys your Redis Enterprise databases (REDB) in the same namespace as the Redis Enterprise cluster (REC). No additional configuration is required for this, since there is no communication required to cross namespaces. See [Deploy Redis Enterprise for Kubernetes]().

title: Single REC and multiple namespaces (one-to-many)

text: Multiple Redis Enterprise databases (REDB) spread across multiple namespaces within the same K8s cluster can be associated with the same Redis Enterprise cluster (REC). See [Manage databases in multiple namespaces]() for more information.

title: Multiple RECs and multiple namespaces (many-to-many)

text:
A single Kubernetes cluster can contain multiple Redis Enterprise clusters (REC), as long as they reside in different namespaces. Each namespace can host only one REC and each operator can only manage one REC.

You have the flexibility to create databases in separate namespaces, or in the same namespace as the REC, or combine any of the supported deployment options above. This configuration is geared towards use cases that require multiple Redis Enterprise clusters with greater isolation or different cluster configurations.

See [Manage databases in multiple namespaces]() for more information.

title: Unsupported deployment patterns

title: Cross-cluster operations

text: Redis Enterprise for Kubernetes does not support operations that cross Kubernetes clusters. Redis Enterprise clusters (REC) work inside a single K8s cluster. Crossing clusters could result in functional and security issues.

title: Multiple RECs in one namespace

text: Redis Enterprise for Kubernetes does not support multiple Redis Enterprise clusters (REC) in the same namespace. Creating more than one REC in the same namespace will result in errors.


title: Redis Enterprise for Kubernetes architecture

summary: Overview of the architecture and components of Redis Enterprise for Kubernetes.

title: Flexible deployment options

title: Overview

text: Redis Enterprise for Kubernetes gives you the speed and durability of [Redis Enterprise](https://redis.io/redis-enterprise/advantages/), with the flexibility and ease of [Kubernetes (K8s)](https://kubernetes.io/). Redis Enterprise for Kubernetes uses the Kubernetes operator pattern and custom controllers to bring the best of Redis Enterprise to the Kubernetes platform.

title: Lifecycle

text:
Kubernetes is a rapidly evolving platform with a short release cycle (around 4 months). This frequent influx of new features, enhancements and bug fixes means Kubernetes distributions move in and out of support quickly. Redis Enterprise is also a fast-moving product, and is compatible and tested only on distributions listed as [supported distributions.]()

Each version of Redis Enterprise for Kubernetes is tested to ensure the version of Redis Enterprise works with the [supported Kubernetes distributions]() at the time. Both the Kubernetes version and the Redis Enterprise version must be supported for the operator to function correctly. We encourage you to upgrade Redis Enterprise for Kubernetes frequently, not only to get the benefit of enhancements and bug fixes, but to keep your software supported.

Supported platforms are listed in the [release notes]() and in the [supported platforms reference.]()

title: Architecture

text: The image below illustrates the components of a single namespace, three node deployment.

title: Operator

text:
An [operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) is a custom extension of the Kubernetes API designed to manage complex, stateful applications and their components. This operator pattern is commonly used by databases and other applications to extend the cluster's behavior without changing its underlying code. Kubernetes.io/docs has a great explanation of the [operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/).

The operator is a deployment that runs within a [namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) and uses [controllers](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#custom-controllers) to manage [custom resources (CRs)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/), ensuring these resources are continuously monitored and maintained.

When the operator is installed, the following resources are created:

- [service account](https://kubernetes.io/docs/concepts/security/service-accounts/) under which the operator will run
- set of [roles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-and-clusterrole) to define the privileges necessary for the operator to perform its tasks
- set of [role bindings](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) to authorize the service account
- [CustomResourceDefinition (CRD)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) for each Redis Enterprise custom resource
- the operator deployment

title: Namespace

text:
The Redis Enterprise [operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) is deployed within a [namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/). Each namespace can host only one operator and one [RedisEnterpriseCluster (REC)](#redisenterprisecluster-rec). Namespaces create logical boundaries between resources, allowing organization and security. Some resources are limited to a namespace, while others are cluster-wide.

Redis Enterprise for Kubernetes also supports [multi-namespace deployments](), meaning the operator can monitor other namespaces (that host applications) for custom resources and apply any changes.

title: Custom resources

text:
Kubernetes [custom resources (CRs)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) are commonly used by databases and other applications to extend the cluster's behavior without changing its underlying code. [Custom resources (CRs)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) extend the Kubernetes API, enabling users to manage Redis databases the Kubernetes way. Custom resources are created and managed using YAML configuration files.

This [declarative configuration approach](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/declarative-config/) allows you to specify the desired state for your resources, and the operator makes the necessary changes to achieve that state. This simplifies [installation](), [upgrades](), and [scaling]() both vertically and horizontally.

The operator continuously monitors CRs for changes, automatically reconciling any differences between the desired state you specified in your YAML configuration file, and the actual state of your resources. Custom resources can also reside in separate namespaces from the operator managing them, such as in [multi-namespace installations]().

title: Custom resource definitions

text:
A [custom resource definition (CRD)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) is a cluster-wide resource that specifies which settings can be configured via custom resource files. Any setting not defined by the CRD is not managed by the operator. You can still make changes to these unmanaged settings using standard Redis Enterprise Software methods.

For settings managed by the operator, any changes made outside of the CR YAML files (e.g., through the management UI) will be overwritten by the operator. Ensure that all operator-managed settings are updated using the CR YAML files to prevent conflicts.

title: RedisEnterpriseCluster REC

text:
A Redis Enterprise cluster is a set of Redis Enterprise nodes pooling resources. Each node is capable of running multiple Redis instances ([shards]()).

A Redis cluster is created and managed by the [RedisEnterpriseCluster (REC)]() [custom resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/). Changes to the REC configuration file prompt the operator to make changes to the cluster. The REC is required for both standard databases ([REDB](#redisenterprisedatabase-redb)) and Active-Active databases ([REAADB](#redisenterpriseactiveactivedatabase-reaadb)).

See the [RedisEnterpriseCluster API Reference]() for a full list of fields and settings.

title: RedisEnterpriseDatabase REDB

text:
A Redis Enterprise database is a logical entity that manages your entire dataset across multiple Redis instances. A Redis instance is a single-threaded database process ([commonly referred to as a shard]()).

Redis databases are created and managed by the [RedisEnterpriseDatabase (REDB)]() [custom resource (CR)](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/). Changes to the REDB YAML configuration file prompt the operator to make changes to the database.

An operator can manage a database in the same namespace, or a different namespace. See ["Flexible deployment"]() options and ["Manage databases in multiple namespaces"]() for more information.

See the [RedisEnterpriseDatabase (REDB) API Reference]() for a full list of fields and settings.

title: Security

text: Redis Enterprise for Kubernetes uses [secrets](https://kubernetes.io/docs/concepts/configuration/secret/) to manage your cluster credentials, cluster certificates, and client certificates. You can configure [LDAP]() and [internode encryption]() using the [RedisEnterpriseCluster (REC)](#redisenterprisecluster-rec) spec.

title: REC credentials

text:
Redis Enterprise for Kubernetes uses the [RedisEnterpriseCluster (REC)]() [custom resource](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) to create a Redis Enterprise cluster. During creation it generates random credentials for the operator to use. The credentials are saved in a Kubernetes (K8s) [secret](https://kubernetes.io/docs/concepts/configuration/secret/). The secret name defaults to the name of the cluster.

See [Manage REC credentials]() for more details.

title: REC certificates

text:
By default, Redis Enterprise Software for Kubernetes generates TLS certificates for the cluster during creation. These self-signed certificates are generated on the first node of each Redis Enterprise cluster (REC) and are copied to all other nodes in the cluster.

See [Manage REC certificates]() for more details.

title: Client certificates

text:
For each client certificate you want to use, you need to create a [Kubernetes secret](https://kubernetes.io/docs/concepts/configuration/secret/) to hold it. You can then reference that secret in your [Redis Enterprise database (REDB)](#redisenterprisedatabase-redb) custom resource.

See [Add client certificates]() for more details.

title: Storage

text:
[Persistent storage is mandatory for Redis Enterprise.]() Redis Enterprise for Kubernetes [requires network-attached storage](https://en.wikipedia.org/wiki/Network-attached_storage).

Redis Enterprise for Kubernetes uses [PersistentVolumeClaims (PVC)](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims) to manage storage resources. The PVC is an abstract representation of the [PersistentVolume (PV)](https://kubernetes.io/docs/concepts/storage/persistent-volumes) resources used by your Redis pods. PVCs are created by the Redis Enterprise operator and used by the [RedisEnterpriseCluster (REC)](#redisenterprisecluster-rec).

PVCs are created with a specific size and [can be expanded](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims), if the underlying [storage class](https://kubernetes.io/docs/concepts/storage/storage-classes/) supports it.

title: Redis Flex

text:
Redis Enterprise Software for Kubernetes supports [Redis Flex]() (previously known as Redis on Flash), which extends your node memory to use both RAM and flash storage. SSDs (solid state drives) can store infrequently used (warm) keys and values while frequently used (hot) keys and values are stored in RAM. This improves performance and lowers costs for large datasets.

NVMe (non-volatile memory express) SSDs are strongly recommended to achieve the best performance.

title: Networking

text:
By default, Kubernetes doesn't allow you to access your Redis database from outside your K8s cluster. Redis Enterprise for Kubernetes supports several ways to route external traffic to your [Redis Enterprise cluster (REC)](#redisenterprisecluster-rec):

- Ingress controllers [HAProxy](https://haproxy-ingress.github.io/) and [NGINX](https://kubernetes.github.io/ingress-nginx/) require an `ingress` API resource.
- [Istio](https://istio.io/latest/docs/setup/getting-started/) requires `Gateway` and `VirtualService` API resources.
- OpenShift uses [routes]() to route external traffic.

The [Active-Active databases](#active-active-databases) require one of above routing methods to be configured in the REC with the [ingressOrRouteSpec field]().

title: Services Rigger

text:
The services rigger is responsible for creating and updating services related to database objects. It identifies database objects within the cluster and creates services in accordance with [`redisEnterpriseCluster.Spec.servicesRiggerSpec` setting]() to allow access to those databases. By default, each database has two services, a `cluster_ip` Service with the same name as the database and a `headless` Service with the same name as the database suffixed with `-headless`. It also creates other types of Services such as Ingress Services or OpenshiftRoutes (defined in `redisEnterpriseCluster.Spec.ingressOrRouteSpec`) meant to provide access to REAADB objects.

You can view a list of services with the `kubectl get services` command.

Kubernetes is a dynamic environment, with nodes and pods changing as needed. The services rigger monitors the cluster for these changes and updates the database services to ensure reliable communication with the databases.

title: Active-Active databases

text:
On Kubernetes, Redis Enterprise [Active-Active]() databases provide read and write access to the same dataset from different Kubernetes clusters. Creating an Active-Active database requires routing [network access]() between two Redis Enterprise clusters residing in different Kubernetes clusters. Without the proper access configured for each cluster, syncing between the databases instances will fail.The admission controller is also required for Active-Active databases on Kubernetes, to validate changes to the custom resources.

For more details and installation information, see [Active-Active databases](). For more general information about Active-Active, see the [Redis Enterprise Software docs]().

title: RedisEnterpriseRemoteCluster RERC

text:
The [RedisEnterpriseRemoteCluster (RERC)]() contains details allowing the REC to link to the RedisEnterpriseActiveActiveDatabase (REAADB). The RERC resource is listed in the [REAADB](#redisenterpriseactiveactivedatabase-reaadb) resource to become a participating cluster for the Active-Active database.

See the [RERC API reference]() for a full list of fields and settings.

title: RedisEnterpriseActiveActiveDatabase REAADB

text:
The RedisEnterpriseActiveActiveDatabase (REAADB) resource creates and manages a database that spans more than one Kubernetes cluster. An REAADB requires [external routing](#networking), at least two [RECs](#redisenterprisecluster-rec), and at least two [RERCs](#redisenterpriseremotecluster-rerc).

See the [REAADB API reference]() for a full list of fields and settings.

title: Metrics

text: To collect  metrics data from your databases and Redis Enterprise cluster (REC), you can [connect your Prometheus]() server to an endpoint exposed on your REC. Redis Enterprise for Kubernetes creates a dedicated service to expose the `prometheus` port (8070) for data collection. A custom resource called `ServiceMonitor` allows the [Prometheus operator](https://github.com/prometheus-operator/prometheus-operator/tree/main/Documentation) to connect to this port and collect data from Redis Enterprise.