# Multitenancy on Entando
This tutorial describes how to configure Entando to serve multiple tenants. The primary tenant is configured first, then secondary tenants can be added. See Multitenancy on Entando for details on concepts and architecture.
# Prerequisites
- A working instance of Entando 7.2 or higher based on the Tomcat server image. This is the default
standardServerImage
for theEntandoApp
custom resource.
# Configure the Primary Tenant
The primary tenant is configured with services for the content delivery server (CDS), cache management, and search capability. Follow the links below to complete the setup.
Install and enable the Entando Content Delivery Server (CDS) to manage static resources.
Install and enable Redis to handle caching and clustering.
Install and enable Solr integration to enable enterprise search.
# Configure the Secondary Tenant
For each secondary tenant, you will need to configure Keycloak, CDS, Solr, and a database schema. Then the ingress and a shared configuration Secret is created, after which the Entando App Engine is modified to read that Secret.
# Definitions
Placeholder | Description |
---|---|
YOUR-APP-NAME | The name of the application, e.g., quickstart |
YOUR-HOST-NAME | The base host name of the application, e.g., your-domain.com |
YOUR-TENANT-NAME | The identifying name of the current tenant. In most cases, it will also be used to determine the base URL of the tenant. For example, yoursite results in yoursite.your-domain.com. |
YOUR-NAMESPACE | The Kubernetes namespace in which your app is running |
# Keycloak
Each tenant requires its own Keycloak realm. Create the tenant-specific realm in the standard Entando-deployed Keycloak instance.
- Create a Backup of the Keycloak Realm
- Remove the
id
attributes so Keycloak will recognize the data as new entries upon importing:
sed -i '' '/"id" : "/ d' keycloak-realm.json
- Replace the
realm
anddisplayName
properties with YOUR-TENANT-NAME. Note: supply the original realm name if it was not namedentando
.
sed -i '' 's/"entando"/"YOUR-TENANT-NAME"/g' keycloak-realm.json
- Update the values of
redirectUris
andwebOrigins
to use YOUR-TENANT-NAME:
sed -i '' 's/\/\/YOUR-APP-NAME\./\/\/YOUR-TENANT-NAME\.YOUR-APP-NAME\./g' keycloak-realm.json
This should transform the URIs from
http(s)://YOUR-APP-NAME.YOUR-HOST-NAME
tohttp(s)://YOUR-TENANT-NAME.YOUR-APP-NAME.YOUR-HOST-NAME
.
Log in to your Keycloak admin console.
Go to
Select realm
in the top left nav →Add Realm
→ select your keycloak-realm.json file. ClickCreate
.In the new realm, go to
Clients
→ Click the Client ID withYOUR-APP_NAME
. Under theCredentials
tab, regenerate theSecret
.
Note: The Secret for this client will be needed in the
entando-tenants-secret.yaml
for the propertykcClientSecret
valueYOUR-TENANT-KC-SECRET
below.
- Regenerate the Secret for Client ID
YOUR-APP-NAME-de
.
Note: The Secret for this client is also required in the
entando-tenants-secret.yaml
, for the propertydeKcClientSecret
valueYOUR-KEYCLOAK-CLIENT-SECRET
below.
Go to
Manage
→Users
. ClickView all users
and choose theadmin
user. Go to Role Mapping and make this assignment: Clientrealm-management
and Rolemanage-realm
.(Optional) Go to
Credentials
and reset the password for theadmin
user.
# Content Delivery Server (CDS)
Each tenant requires its own set of CDS resources. Follow the CDS tutorial to prepare these resources for each secondary tenant.
# Solr
Each tenant requires a dedicated Solr core or collection. Follow the Solr tutorial to generate the core and schema for each secondary tenant.
# Database
Each tenant requires a new database schema for the Entando tables related to the page structure, web content, widgets, etc. The following steps provide a way to export the schemas in a default installation using the Entando-generated PostgreSQL instance. The exact commands will differ for external databases and other DBMS.
- Determine the name of your PostgreSQL pod (YOUR-POSTGRESQL-POD):
kubectl get pods | grep postgres
Example:
default-postgresql-dbms-in-namespace-deployment-54bb664745lxllh
- Determine the names of the three source schemas:
kubectl exec -it YOUR-POSTGRESQL-POD -- psql -d default_postgresql_dbms_in_namespace_db -c "SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE '%portdb%' OR schema_name LIKE '%servdb%' OR schema_name LIKE '%dedb%';"
Example:
quickstart_portdb_90419
quickstart_servdb_90314
quickstart_dedb_9472
Use these values for YOUR-SCHEMA-1, YOUR-SCHEMA-2, and YOUR-SCHEMA-3 in the following steps.
- Export the schemas:
kubectl exec -it YOUR-POSTGRESQL-POD -- pg_dump -O -n YOUR-SCHEMA-1 -n YOUR-SCHEMA-2 -n YOUR-SCHEMA-3 default_postgresql_dbms_in_namespace_db > db_export.sql
- Replace the schema names in the export file:
sed -i'' 's/YOUR-SCHEMA-1/YOUR-TENANT-NAME/g; s/YOUR-SCHEMA-2/YOUR-TENANT-NAME/g; s/YOUR-SCHEMA-3/YOUR-TENANT-NAME/g' db_export.sql
Note: The default Entando implementation used for the primary tenant has two schemas (portdb and servdb) but these are combined into a single schema for secondary tenants.
- Import the new schema into PostgreSQL:
kubectl exec -it YOUR-POSTGRESQL-POD -- psql -d default_postgresql_dbms_in_namespace_db < db_export.sql
- Truncate the Liquibase-managed log lock table to avoid issues with schema updates:
kubectl exec -it YOUR-POSTGRESQL-POD -- psql -d default_postgresql_dbms_in_namespace_db -c "TRUNCATE YOUR-TENANT-NAME.databasechangeloglock;"
# Tenant Configurations
# Tenant Ingress
- Download the template
entando-tenant-ingress.yaml
:
curl -sLO "https://raw.githubusercontent.com/entando/entando-releases/v7.3.0/dist/ge-1-1-6/samples/entando-tenant-ingress.yaml"
- Create an ingress for your primary and each of your secondary tenants. Replace the placeholders with the appropriate values for each tenant. Remember, YOUR-TENANT-NAME will change for each ingress you create.
- For every secondary tenant, add the following snippet with its tenant name under
metadata.labels
:EntandoTenant: YOUR-TENANT-NAME
- For every secondary tenant, add the following snippet with its tenant name under
- Apply each Ingress with the following command:
kubectl apply -f YOUR-TENANT-NAME-INGRESS.yaml -n YOUR-NAMESPACE
# Tenant Configuration Secret
A single Secret needs to be defined with the configuration for each of the tenants. If the entando-tenants-secret.yaml
already exists, then it should be edited with the addition of a new JSON block for the tenant.
- Download the template
entando-tenants-secret.yaml
:
curl -sLO "https://raw.githubusercontent.com/entando/entando-releases/v7.3.0/dist/ge-1-1-6/samples/entando-tenants-secret.yaml"
Replace the placeholders with the appropriate values for each of your tenants.
Create the Secret:
kubectl apply -f entando-tenant-secret.yaml -n YOUR-NAMESPACE
# Configure the EntandoApp
The EntandoApp has to be configured just once to point to the entando-tenants-secret.yaml
. When additional tenants are added, the EntandoApp deployment only needs to be restarted.
- Scale down the EntandoApp deployment to 0:
kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=0 -n YOUR-NAMESPACE
- Edit the deployment YAML and add the environment variable to point to the K8s Secret.
-env:
- name: ENTANDO_TENANTS
valueFrom:
secretKeyRef:
name: entando-tenants-secret
key: ENTANDO_TENANTS
optional: false
- Scale the deployment back up to 1 or more replicas:
kubectl scale deploy/YOUR-APP-NAME-deployment --replicas=1 -n YOUR-NAMESPACE
- Confirm that the secondary tenant is working correctly. This may include testing the EntandoApp itself (including digital assets delivered via CDS), the AppBuilder, and enterprise search for Solr. The tutorials for each service include verification steps that can be followed once the tenant configuration is fully in place.
# Bundles
Once tenants are in order, Entando Bundles can be deployed independently to each tenant from registries added in the App Builder. Bundles can be centralized in an enterprise Entando Hub where all tenants can access them by adding the registry in the Local Hub of the App Builder.
When bundles are installed to any tenant, the Component Manager injects an ENTANDO_TENANT_CODE
, an environment variable related to the tenant domain name, into every microservice, identifying which tenant it belongs to.
To create or adapt bundles for multitenant applications, environment variables can be leveraged in the bundle descriptor to customize bundles. Microservices can be specified with an embedded or internal SQL DBMS, but if an external database is required, a plugin configuration Secret will need to be configured.
- Create and Publish a Bundle project
- Learn about Entando Bundles
- Add an enterprise Entando Hub
- Add a Registry to you Local Hub
- Configure External DBMS for Microservices
# Appendix
# Liquibase Options
Liquibase is the default for database management for multitenancy on Entando, but this process can be modified with the following methods.
Apply the Strategy in the App Engine Deployment
Use this specification in the entando-de-app
image to set the strategy for all tenants, including the primary and secondary tenants.
db.migration.strategy
: "skip|disabled|auto|generate_sql" # defaults to 'auto' which uses Liquibase to initialize checks and updates on the DBs
Apply the Strategy for Secondary Tenants
For a secondary tenant, the dbMigrationStrategy
value in the entando-tenant-secret.yaml
can be modified to specify its behavior.
dbMigrationStrategy
: "skip|disabled|auto|generate_sql" # default is 'skip'; to skip the entire Liquibase process of checking databasechangelog tables and changeSetFilesIf
dbMigrationStrategy
is not present inside the tenant configuration, it looks for the value in thedb.migration.strategy
system property.
# Tenant Domains
A tenant can have multiple fully qualified domain names (FQDNs), as long as they are defined in the fqdns
field of the tenant configuration secret. This field determines which tenant's configuration to use when an incoming request is made to the Entando Application.
Example:
"fqdns": "www.YOUR-HOST-NAME,blog.YOUR-HOST-NAME,news.YOUR-HOST-NAME"
# Tomcat Options
Entando's multitenancy application uses the Tomcat servlet container and provides a few optional parameters.
Enabling a Java Agent for Tomcat
To use a Java agent with your application, use initContainers with a PVC (PersistenVolumeClaim) to prepare the JAR file with the information required for the agent. Add the following environment variables to the entando-de-app-tomcat
deployment to activate the agent and provide the agent code from the JAR file.
AGENT_ENABLED: "true" # if true, adds the agent options to tomcat, defaults to false
AGENT_OPTS: "-javaagent:~/YOUR-JARFILE.jar" # the jar file with the agent options to use, defaults to empty
Manage Upload File Size Limitations
Add these environment variables to the entando-de-app-tomcat
deployment to customize the application-server and file upload maximum sizes.
For the Tomcat application server, use
TOMCAT_MAX_POST_SIZE
to configure connector maxPostSize; the default value is 209,715,200 bytes. Enter the value in bytes.For the application, use
FILE_UPLOAD_MAX_SIZE
to configure the upload limit; the default value is 52,428,800 bytes. Enter the value in bytes.