|
| 1 | +--- |
| 2 | +Title: Create Active-Active databases with crdb-cli |
| 3 | +alwaysopen: false |
| 4 | +categories: |
| 5 | +- docs |
| 6 | +- operate |
| 7 | +- kubernetes |
| 8 | +description: This section shows how to set up an Active-Active Redis Enterprise database |
| 9 | + on Kubernetes using the Redis Enterprise Software operator. |
| 10 | +linkTitle: Create Active-Active with crdb-cli |
| 11 | +weight: 99 |
| 12 | +url: '/operate/kubernetes/7.4.6/active-active/create-aa-crdb-cli/' |
| 13 | +--- |
| 14 | +{{<note>}} 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]({{< relref "/operate/kubernetes/active-active/create-reaadb.md" >}}).{{</note>}} |
| 15 | + |
| 16 | +On Kubernetes, Redis Enterprise [Active-Active]({{< relref "/operate/rs/databases/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]({{< relref "/operate/rs/databases/active-active/" >}}). |
| 17 | + |
| 18 | +Creating an Active-Active database requires routing [network access]({{< relref "/operate/kubernetes/networking/" >}}) 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. |
| 19 | + |
| 20 | +This process consists of: |
| 21 | + |
| 22 | +1. Documenting values to be used in later steps. It's important these values are correct and consistent. |
| 23 | +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. |
| 24 | +1. Creating the database with the `crdb-cli` command. These values must match up with values in the REC resource spec. |
| 25 | + |
| 26 | +## Prerequisites |
| 27 | + |
| 28 | +Before creating Active-Active databases, you'll need admin access to two or more working Kubernetes clusters that each have: |
| 29 | + |
| 30 | +- Routing for external access with an [ingress resources]({{< relref "/operate/kubernetes/networking/ingress.md" >}}) (or [route resources]({{< relref "/operate/kubernetes/networking/routes.md" >}}) on OpenShift). |
| 31 | +- A working [Redis Enterprise cluster (REC)]({{< relref "/operate/kubernetes/reference/redis_enterprise_cluster_api" >}}) with a unique name. |
| 32 | +- Enough memory resources available for the database (see [hardware requirements]({{< relref "/operate/rs/installing-upgrading/install/plan-deployment/hardware-requirements.md" >}})). |
| 33 | + |
| 34 | +{{<note>}} 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.{{</note>}} |
| 35 | + |
| 36 | +## Document required parameters |
| 37 | + |
| 38 | +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. |
| 39 | + |
| 40 | +- **Database name** `<db-name>`: |
| 41 | + - Description: Combined with ingress suffix to create the Active-Active database hostname |
| 42 | + - Format: string |
| 43 | + - Example value: `myaadb` |
| 44 | + - How you get it: you choose |
| 45 | + - The database name requirements are: |
| 46 | + - Maximum of 63 characters |
| 47 | + - Only letter, number, or hyphen (-) characters |
| 48 | + - Starts with a letter; ends with a letter or digit. |
| 49 | + - Database name is not case-sensitive |
| 50 | + |
| 51 | +You'll need the following information for each participating Redis Enterprise cluster (REC): |
| 52 | + |
| 53 | +{{<note>}} |
| 54 | +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). |
| 55 | +{{</note>}} |
| 56 | + |
| 57 | +- **REC hostname** `<rec-hostname>`: |
| 58 | + - Description: Hostname used to identify your Redis Enterprise cluster in the `crdb-cli` command. This MUST be different from other participating clusters. |
| 59 | + - Format: `<rec-name>.<namespace>.svc.cluster.local` |
| 60 | + - Example value: `rec01.ns01.svc.cluster.local` |
| 61 | + - How to get it: List all your Redis Enterprise clusters |
| 62 | + ```bash |
| 63 | + kubectl get rec |
| 64 | + ``` |
| 65 | +- **API hostname** `<api-hostname>`: |
| 66 | + - Description: Hostname used to access the Redis Enterprise cluster API from outside the K8s cluster |
| 67 | + - Format: string |
| 68 | + - Example value: `api.ijk.example.com` |
| 69 | +- **Ingress suffix** `<ingress-suffix>`: |
| 70 | + - Description: Combined with database name to create the Active-Active database hostname |
| 71 | + - Format: string |
| 72 | + - Example value: `-cluster.ijk.example.com` |
| 73 | +- [**REC admin credentials**]({{< relref "/operate/kubernetes/security/manage-rec-credentials.md" >}}) `<username> <password>`: |
| 74 | + - Description: Admin username and password for the REC stored in a secret |
| 75 | + - Format: string |
| 76 | + - Example value: username: `user@example.com`, password: `something` |
| 77 | + - How to get them: |
| 78 | + ```sh |
| 79 | + kubectl get secret <rec-name> \ |
| 80 | + -o jsonpath='{.data.username}' | base64 --decode |
| 81 | + kubectl get secret <rec-name> \ |
| 82 | + -o jsonpath='{.data.password}' | base64 --decode |
| 83 | + ``` |
| 84 | +- **Replication hostname** `<replication-hostname>`: |
| 85 | + - Description: Hostname used inside the ingress for the database |
| 86 | + - Format: `<db-name><ingress-suffix>` |
| 87 | + - Example value: `myaadb-cluster.ijk.example.com` |
| 88 | + - How to get it: Combine `<db-name>` and `<ingress-suffix`> values you documented above. |
| 89 | +- **Replication endpoint** `<replication-endpoint>`: |
| 90 | + - Description: Endpoint used externally to contact the database |
| 91 | + - Format: `<db-name><ingress-suffix>:443` |
| 92 | + - Example value: `myaadb-cluster.ijk.example.com:443` |
| 93 | + - How to get it:`<replication-hostname>:443` |
| 94 | + |
| 95 | +## Add `activeActive` section to the REC resource file |
| 96 | + |
| 97 | +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. |
| 98 | + |
| 99 | + 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>. |
| 100 | +
|
| 101 | +### Using ingress controller |
| 102 | +
|
| 103 | +1. If your cluster uses an [ingress controller]({{< relref "/operate/kubernetes/networking/ingress.md" >}}), add the following to the `spec` section of your REC resource file. |
| 104 | +
|
| 105 | + Nginx: |
| 106 | +
|
| 107 | + ```sh |
| 108 | + activeActive: |
| 109 | + apiIngressUrl: <api-hostname> |
| 110 | + dbIngressSuffix: <ingress-suffix> |
| 111 | + ingressAnnotations: |
| 112 | + kubernetes.io/ingress.class: nginx |
| 113 | + nginx.ingress.kubernetes.io/backend-protocol: HTTPS |
| 114 | + nginx.ingress.kubernetes.io/ssl-passthrough: "true" |
| 115 | + method: ingress |
| 116 | + ``` |
| 117 | +
|
| 118 | +HAproxy: |
| 119 | +
|
| 120 | + ```sh |
| 121 | + activeActive: |
| 122 | + apiIngressUrl: <api-hostname> |
| 123 | + dbIngressSuffix: <ingress-suffix> |
| 124 | + ingressAnnotations: |
| 125 | + kubernetes.io/ingress.class: haproxy |
| 126 | + ingress.kubernetes.io/ssl-passthrough: "true" |
| 127 | + method: ingress |
| 128 | + ``` |
| 129 | +
|
| 130 | +2. After the changes are saved and applied, you can verify a new ingress was created for the API. |
| 131 | +
|
| 132 | + ```sh |
| 133 | + $ kubectl get ingress |
| 134 | + NAME HOSTS ADDRESS PORTS AGE |
| 135 | + rec01 api.abc.cde.example.com 225161f845b278-111450635.us.cloud.com 80 24h |
| 136 | + ``` |
| 137 | +
|
| 138 | +3. Verify you can access the API from outside the K8s cluster. |
| 139 | +
|
| 140 | + ```sh |
| 141 | + curl -k -L -i -u <username>:<password> https://<api-hostname>/v1/cluster |
| 142 | + ``` |
| 143 | +
|
| 144 | + 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. |
| 145 | + |
| 146 | +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`). |
| 147 | + |
| 148 | +#### If using Istio Gateway and VirtualService |
| 149 | + |
| 150 | +No changes are required to the REC spec if you are using [Istio]({{< relref "/operate/kubernetes/networking/istio-ingress.md" >}}) 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. |
| 151 | + |
| 152 | +{{<warning>}} |
| 153 | +These custom resources are not controlled by the operator and will need to be configured and maintained manually. |
| 154 | +{{</warning>}} |
| 155 | + |
| 156 | +For each cluster, verify the VirtualService resource has two `- match:` blocks in the `tls` section. The hostname under `sniHosts:` should match your `<replication-hostname>`. |
| 157 | + |
| 158 | +### Using OpenShift routes |
| 159 | + |
| 160 | +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. |
| 161 | + You can check your new REC name with: |
| 162 | + ```sh |
| 163 | + oc get rec -o jsonpath='{.items[0].metadata.name}' |
| 164 | + ``` |
| 165 | +
|
| 166 | + 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. |
| 167 | + |
| 168 | + ```sh |
| 169 | + oc apply -f scc.yaml |
| 170 | + oc adm policy add-scc-to-group redis-enterprise-scc-v2 system:serviceaccounts:<namespace> |
| 171 | + ``` |
| 172 | +
|
| 173 | + Releases before 6.4.2-6 use the earlier version of the SCC, named `redis-enterprise-scc`. |
| 174 | +
|
| 175 | +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`). |
| 176 | +
|
| 177 | +1. If your cluster uses [OpenShift routes]({{< relref "/operate/kubernetes/networking/routes.md" >}}), add the following to the `spec` section of your Redis Enterprise cluster (REC) resource file. |
| 178 | +
|
| 179 | + ```sh |
| 180 | + activeActive: |
| 181 | + apiIngressUrl: <api-hostname> |
| 182 | + dbIngressSuffix: <ingress-suffix> |
| 183 | + method: openShiftRoute |
| 184 | + ``` |
| 185 | +
|
| 186 | +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`). |
| 187 | +
|
| 188 | +1. After the changes are saved and applied, you can see that a new route was created for the API. |
| 189 | +
|
| 190 | + ```sh |
| 191 | + $ oc get route |
| 192 | + NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD |
| 193 | + rec01 api-openshift.apps.abc.example.com rec01 api passthrough None |
| 194 | + ``` |
| 195 | +
|
| 196 | +## Create an Active-Active database with `crdb-cli` |
| 197 | +
|
| 198 | +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]({{< relref "/operate/kubernetes/active-active/create-aa-crdb-cli#document-required-parameters" >}}) for each Redis Enterprise cluster. |
| 199 | + |
| 200 | +```sh |
| 201 | +crdb-cli crdb create \ |
| 202 | + --name <db-name> \ |
| 203 | + --memory-size <mem-size> \ |
| 204 | + --encryption yes \ |
| 205 | + --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> \ |
| 206 | + --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> |
| 207 | +``` |
| 208 | + |
| 209 | +To create a database that syncs between more than two instances, add additional `--instance` arguments. |
| 210 | + |
| 211 | +See the [`crdb-cli` reference]({{< relref "/operate/rs/references/cli-utilities/crdb-cli" >}}) for more options. |
| 212 | + |
| 213 | +## Test your database |
| 214 | + |
| 215 | +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. |
| 216 | + |
| 217 | +You can connect to your databases with the instructions in [Manage databases]({{< relref "/operate/kubernetes/re-databases/db-controller#connect-to-a-database" >}}). 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`. |
0 commit comments