Building a Multi-tenanted SaaS with Node.js
-
Upload
eoin-shanaghy -
Category
Technology
-
view
64 -
download
6
Transcript of Building a Multi-tenanted SaaS with Node.js
![Page 1: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/1.jpg)
111 Steps to Building a Multi-tenanted SaaS in Node.js
Eoin Shanaghy
Edappy
eoinseoinsha
![Page 2: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/2.jpg)
Edappy started with a single-tenanted internal system, delivering University-level courses
Node.js - Seneca - Express - MongoDB
Microservices
Dockerised EC2
The job: Make the platform a multi-tenanted SaaS
![Page 3: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/3.jpg)
The Beginning
![Page 4: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/4.jpg)
“This should be easy”a.edappy.com b.edappy.com
c.edappy.com d.edappy.com
![Page 5: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/5.jpg)
We started to think about Tenant Provisioning.
“How often?”
“How big?”
“How does it relate to the business model?”
“How will we…monitor it, maintain it or deploy it?”
![Page 6: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/6.jpg)
We will have many small tenants. Some will be just evaluating, at least at first. They will be spread internationally and many will use a free tier.
A few will be large, enterprise tenants. They will take longer to publish their content but will have many thousands of students and many, large courses.
![Page 7: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/7.jpg)
Don’t just think production.How do I run a multi-tenanted SaaS in development?
What will my tests look like?
How many processes, containers and VMs will I need to run?
![Page 8: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/8.jpg)
First, share.Duplicating anything increases overhead.
Share resources where possible.
Isolate only when required.
![Page 9: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/9.jpg)
No new hardware.Before adding any containers or instances, maximise every bit of existing infrastructure.
Faster start.
Lower maintenance.
More cost effective.
![Page 10: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/10.jpg)
![Page 11: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/11.jpg)
Actually, one new container
![Page 12: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/12.jpg)
IsolationThere are three ways to isolate tenants’ data.
Document/table per tenant
Collection/Table per tenant
Database per tenant
![Page 13: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/13.jpg)
HTTP - Express - Seneca - Actor - MongoDB
![Page 14: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/14.jpg)
http://senecajs.org/tutorials/understanding-data-entities.html
![Page 15: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/15.jpg)
$> mongo test --eval “shellPrint(db.person.find())"{ "_id" : ObjectId("56563ed8f25f27f90cedeafe"), "name" : "Fred", "age" : 17 }
$> mongo test2 --eval “shellPrint(db.person.find())"{ "_id" : ObjectId("56563ed8f25f27f90cedeaff"), "name" : "Elizabeth", "age" : 27 }
![Page 16: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/16.jpg)
Seneca already gives you:
routing
pattern-based segregation/partitioning
The explicit version:
![Page 17: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/17.jpg)
Transparent, in-band context
Within any actor, I want to know which tenant domain initiated the request.
![Page 18: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/18.jpg)
![Page 20: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/20.jpg)
![Page 21: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/21.jpg)
So we wrote…
https://github.com/LSEducation/seneca-context
seneca-context allows you to set or get any data relating to a single request at any point in the action chain, even across transport boundaries
![Page 22: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/22.jpg)
Express
seneca-context
seneca-web
createContext Tenant Registry
action
action
action
transport boundary
POST /api/user/authHost: d.edappy.com
D
D
D
D
“d”?seneca-web plugin
![Page 23: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/23.jpg)
DNSRoute53
Wildcard subdomains first:
*.example.com
*._staging.example.com
*._local.example.com - 127.0.0.1
Programatically registered thereafter
![Page 24: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/24.jpg)
Tenant StoresThere are hundreds of actors
Each actor has 0..* store operations
How do you avoid explicitly setting the zone for every operation?
![Page 25: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/25.jpg)
Write another Seneca pluginUse seneca.wrap
Intercept all entity actions
Look up the zone/context if not already set
Provision the DB, if not already done
Configure the store plugin
Set the zone and call seneca.prior
![Page 26: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/26.jpg)
Now…
![Page 27: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/27.jpg)
Was…
![Page 28: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/28.jpg)
Other parts of the story
![Page 29: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/29.jpg)
HurdlesDon’t create or read any tenant-specific data on init
![Page 30: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/30.jpg)
Tenant ProvisioningRegister a tenant record
Create external resources (bucket)
Configure database
Approximately $0 cost
![Page 31: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/31.jpg)
Integration TestingAt least one instance of each service
At least two tenants
Clean database per suite
Docker Compose
Each test begins outside the app boundary (SuperTest)
Seneca test actions to perform setup/teardown
![Page 32: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/32.jpg)
OversightWe use ELK for aggregated logs across containers and services
Log and index tenant ID
APIs
Actions
Debugging
![Page 33: Building a Multi-tenanted SaaS with Node.js](https://reader033.fdocuments.net/reader033/viewer/2022051318/587fd2a81a28ab58248b4fb3/html5/thumbnails/33.jpg)
ScalingUp to a point, adding instances, containers is okay
Large, high value tenants warrant dedicated resources
Limit tenant-specific resources per app instance (DB connections, etc.)
Explicit/Manual, Mesos, Kubernetes