We go through how you can use Divio Mirrors to build scaleable and secure single-tenant web applications.
Thomas Bailey
Marketing
Single-tenancy architecture is a common approach used by SaaS applications to serve each customer, or tenant, a dedicated and separate instance of an application facilitating scalable app development.
The primary benefit of a single-tenancy architecture is the security inherent in the design. Rather than use a shared data source and federate access through soft controls and configurations, each customer has their own data source, typically residing in separated storage and potentially on entirely different physical mediums. This separation enhances application scalability by allowing resources to be allocated independently.
A single-tenancy architecture also provides each customer with their own set of allocated resources. No single customer can consume the resources of another, ensuring a responsive application and increased availability. Inversely if specific customers place more demands on the application, more resources can be allocated accordingly, scaling up specific instances to meet demand highlighting its effectiveness in scaling applications.
It also becomes possible to provide customers with more specialised variants of the application whilst sharing a consistent code base, applying customer-specific changes to specific scalable app instances. Apps can be offered as a white-label solution that can be customised or branded to customer requirements supporting app scaling for different use cases.
A trade-off typically associated with a single-tenancy architecture is shifting the complexity from the application to the hosting infrastructure, which is crucial when addressing scaling web applications.
This typically means that rather than having one large instance to deploy and maintain, a single-tenant application needs to be deployed and managed for every specific customer, increasing maintenance overhead.
With each instance of the application, more resources are being replicated and consumed, which can lead to increased costs. While a multi-tenant application could serve all customers from a single instance, a single-tenancy architecture implies multiple customer-specific instances, leading to increased complexity and overhead in application management.
Divio built the web app mirroring feature 'Mirrors' to facilitate single-tenancy applications and make them easy to run and manage in a cloud environment, addressing the shortcomings usually associated with the architecture and leveraging the Divio platform to automate away the underlying complexity.
Creating a mirror of your application is an essential part of app scaling, allows one codebase to service multiple application instances. A mirror is a duplicate of a single-tenancy app, which acts as a parent. Each mirror is isolated with its allocated resources, database, media storage, cloud application backup strategies and other services.
Every mirror instance has access to the same tools and features as the parent app and can have a specific plan to best-fit customer demands – giving more resources to specific mirrors and having bespoke backup strategies to meet customer needs.
The Divio approach to Mirrors also creates a new opportunity to adopt a hybrid strategy popular with traditional SaaS models. The parent app can be used to serve a large segment of customers, offering the same base features and “one size fits all”, while mirrors can be used for specific customers, offering specialised features.
The web app we will create will be a simple Node.js app that responds differently according to the instance being used, using one simple codebase.
Before you begin, set up your local working environment with the Divio CLI – a powerful command line tool that allows us to work locally and quickly deploy to the Divio cloud.
Using the Divio Control Panel, create a new project using the Node,js stack and Express addon that Divio has preconfigured, giving us a working Node.js application in a few seconds.
Once we have created the app, we can grab the project locally by running divio app setup divio-mirror-app
– assuming the app name should reflect what you have called your app.
Since we have chosen the Express framework, Divio has already provided some basic barebones functionality to respond to a HTTP request. We can use this as an easy entry point to react differently according to the mirror being used.
Each mirrored application has its own set of environmental variables which we can use to affect behaviour in different ways.
From the Divio Control Panel, set a new environmental variable SITE_ID
for both test and live environments, which we will increment across each mirror we create. We can give it any value that we can use to show the difference between each mirror.
Open the myapp/routes/index.js
, where we can make a simple change to respond to HTTP requests by showing the SITE_ID
variable configured for the application.
router.get('/', function(req, res, next) {
const siteId = process.env.SITE_ID? process.env.SITE_ID : 'Not currently configured'
res.render('index', { title: 'Serving site with id ' + siteId });
});
When the Divio platform created the application, it also configured a Git repository for us. In order to reflect the change in the cloud, we need to stage and commit the change in the usual way.
git add myapp/routes/index.js
git commit -m "Add an environmental variable"
git push
Switching back to the Divio Control Panel, we can see that our commit is now ready to be deployed to the staging environment.
Deploy the change and test the expected result using the URL specific to your application. The SITE_ID
variable should be echoed accordingly.
Before we create a mirror, Divio provides two different duplication types – a fork or a mirror.
A fork means that an entirely new application is created with a duplicate of the current codebase, database and storage, which is a snapshot at the point where the fork is made. The application resulting from forking is entirely separate from the parent app.
Forking can be used when an application requires more substantial or specialised changes to the codebase or when it becomes too cumbersome to service specific customers from a single codebase.
A mirror is a duplicate of the application's production environment, and before we can create a mirror, the production environment should first be deployed. The parent app and its mirrors share the same codebase, and changes can be selectively deployed by filtering the available mirrors. This approach is highly beneficial when scaling web applications, allowing businesses to optimize resources while managing multiple instances efficiently.
We can create a mirror by selecting Duplicate from the application kebab menu (three dots menu) beside the application name and selecting Mirror from the available duplication types.
Each mirror we create will logically reside under its parent application, which we can deploy individually by accessing each mirror separately or using the Mirrors shortcut of the parent application.
Open the mirror instance and increment the SITE_ID
we initially created for the parent application. Note that after changing environment variables, the application should be deployed again to apply the updated environment variable.
We can now preview the parent application and mirror, noting how with one codebase, they respond differently (with the SITE_ID
changing accordingly).
Since we are now using one codebase to serve both the parent application and its mirrors, we can implement shared changes supporting a scalable app architecture.
We can add another endpoint to the application which echoes the domain being used to serve the application. The Divio platform populates several useful variables by default, including DOMAIN
which can we use in our app to highlight how the same codebase is being shared.
Add the new endpoint to the existing application route myapp/routes/index.js
router.get('/domain', function(req, res, next) {
res.render('index', { title: 'Serving site with domain ' + process.env.DOMAIN });
});
Stage, commit and push the changes to deploy the updated app to the Divio cloud.
git add myapp/routes/index.js
git commit -m "Added new endpoint"
git push
From the Divio Control Panel, we can deploy the change to our parent application and, using the Mirrors menu, decide how to cascade the change by deploying specific mirrors.
With both the parent application deployed and the mirror deployed, the new /domain
endpoint becomes available to both the parent and mirror.
Divio Mirrors are a powerful concept that can lead to significant cost savings in cloud resources and development hours, with long-term gains in a more simplified codebase.
Each mirrored application has its own set of resources, including a separate database and storage with powerful tools to deploy changes across flexible customisation, selectively all served from the same code base.
Stay updated on the latest Divio features and improvements through our Changelog.
Contact us to learn more.