How to Host Separate Instances of Your SaaS Software in the Same Kubernetes Cluster

Lukas Gentele
Damaso Sanoja
12 min read

Sharing Kubernetes cluster resources between multiple users or teams, a practice known as multitenancy in Kubernetes, can be a cost-effective solution to deploy software-as-a-service (SaaS) applications.

However, there are several challenges associated with multitenancy. For example, tenants cannot use custom resource definitions (CRDs), install Helm charts that use role-based access control (RBAC), or use a different version of Kubernetes than the cluster where they reside. Furthermore, user management, equitable resource sharing, tenant isolation, and cluster security also pose significant hurdles in multitenant setups.

In this tutorial, you’ll learn how to tackle these challenges using Loft’s vCluster API to launch separate SaaS instances living in virtual Kubernetes clusters within the same Kubernetes cluster.

#Setting Objectives

Since this tutorial focuses on overcoming the pain points associated with Kubernetes multitenancy setups, the software side (SaaS frontend and backend) will be left aside as much as possible. Instead, you’ll be learning how to deploy as many SaaS instances as necessary using simple API calls.

Essentially, this tutorial will enable your team to build powerful API-driven solutions based on the tooling of their choice.


To follow this tutorial, ensure that you have the following:

  • A Kubernetes cluster. This tutorial uses minikube, but you can use any other alternative, local or remote, that suits your preferences.
  • The Helm package manager installed on your local machine.
  • The kubectl command line tool installed and configured on your local machine to access the Kubernetes cluster.

#Setting Up Loft in Your Kubernetes Cluster

You can install Loft in your Kubernetes cluster using Helm or the Loft CLI. For this tutorial, you’ll use the latter since it’s the preferred way to deploy Loft to a Kubernetes cluster.

Assuming your machine is running Linux (AMD64), run the following command to install the Loft CLI:

curl -L -o loft "" && sudo install -c -m 0755 loft /usr/local/bin

Otherwise, follow the instructions in the documentation to download and install the Loft CLI.

Next, deploy Loft and all related components to your current Kubernetes context using this command:

loft start

Behind the scenes, the Loft CLI uses the default values of Loft’s Helm chart to deploy to Kubernetes. Once the components are ready, you’ll see a message similar to the following:

Successfully logged in via CLI into Loft instance
18:57:30 info If the browser does not open automatically, please navigate to

##########################   LOGIN   ############################

Username: admin
Password: 30172a45-a2ec-4384-9749-395efbf7132b  # Change via UI or via: loft reset password

Login via UI:
Login via CLI: loft login


Loft was successfully installed and can now be reached at:

As indicated, a new browser window showing the sign-up screen should open:

Loft sign-up screen

Fill in the requested fields and press Finish, which will take you to the main dashboard:

Loft dashboard

This completes the Loft setup process. You installed the Loft CLI on your local machine, deployed Loft to your Kubernetes cluster, and deployed an instance of Loft UI to the cloud, which constantly reconciles changes with your cluster.

#Loft Platform Overview

Before delving into setting up virtual clusters, it’s essential to provide some context on how the SaaS instances will be organized within the Kubernetes cluster.

The Loft platform offers more than virtual clusters. It provides your organization with features like projects, clusters, spaces, apps, and cost reduction tools that make it easy to manage your Kubernetes cluster. For a high-level overview of these features, refer to the documentation.

For this tutorial, you’ll only use projects and apps.

Projects provide an additional level of abstraction to Kubernetes since they allow you to group virtual clusters and virtual cluster templates under the same roof. More importantly, you can create members and groups for each project, which provides an effective mechanism for controlling who has access to the project and what their permissions are.

Simply put, projects allow you to achieve something like this:

Projects diagram

In the image, you see three projects: one for the development team, one for beta testers, and one for production. Each project has members and groups with different permissions. Furthermore, each project hosts as many virtual clusters as necessary. In this tutorial, you’ll create a project hosting the different SaaS instances.

In terms of apps, they are a perfect fit for this use case. In simple terms, you can package your current SaaS app in a Helm chart (the app) and include it in a virtual cluster template. This way, when you deploy each SaaS instance, you not only define the values of the virtual Kubernetes cluster, but you also automatically deploy everything necessary to run your SaaS software.

Sounds too good to be true? Let’s see how to do it.

#Hosting Separate Instances of Your SaaS Software in Kubernetes Using Loft

In this section, you’ll follow a three-step process:

  1. Create a new project to host your SaaS instances
  2. Add your SaaS app or environment to the list of available apps
  3. Create a virtual cluster template that automatically deploys your SaaS environment in each instance

Once you’ve completed those steps, you’ll then test your virtual cluster template manually before learning how to use it in API calls.

#Creating a New Project

Create a new project to host your SaaS instances. To do this, click Default Project and then New Project:

New Project

This will open a pop-up window where you can configure the project:

Project details

You can edit the YAML manifest or configure project details from the UI. To keep this example simple, create a user and assign it the Project Admin role as shown above. Once ready, click Save Changes to accept the default values, which include access to all virtual clusters and templates within the project.

From the perspective of the Kubernetes host, the project you just created is actually a namespace:

$ kubectl get ns
NAME                   STATUS   AGE
default                Active   19h
flask                  Active   19h
kube-node-lease        Active   19h
kube-public            Active   19h
kube-system            Active   19h
loft                   Active   17h
loft-p-default         Active   17h
loft-p-saas-tutorial   Active   6m50s <--- saas-tutorial project

Loft uses the loft-p-* prefix to identify projects. Keep this in mind, as you will need to use that format when making API calls.

#Adding Your SaaS App

Now that all the virtual resources are grouped under the saas-tutorial project, it’s time to learn how to add your SaaS app to Loft.

Click Templates and then Apps, as shown below:

Apps dashboard

As shown in the screenshot, some applications are already preinstalled. There’s also an “Add App” button that allows you to add your own. But first, click the Example Helm App. That will open a pop-up window showing app details:

Example Helm App

As you can see, you can deploy applications using kubectl, Helm charts, or even a Bash script. In the case of Helm, you can add an app by specifying the chart name, version, repository, and chart values.

Now, close the pop-up window and click the Add App button. The screenshot below shows the details for installing a dummy app called my-saas-app using kubectl:


This app consists of a web server and a service that exposes it. Copy the following Kubernetes manifest and paste it into the UI before continuing:

apiVersion: apps/v1
kind: Deployment
  name: my-saas-app
      app: my-saas-app
  replicas: 3
        app: my-saas-app
      - name: my-app-container
        image: nginx:latest
        - containerPort: 80
apiVersion: v1
kind: Service
  name: my-app-service
  type: LoadBalancer
    - port: 8080
      targetPort: 80
    app: my-saas-app

Once ready, click Create App to save the settings.

That’s it—the SaaS app is ready. Now, you must associate it with a virtual cluster template so that the app is deployed with each new SaaS instance.

#Creating Virtual Cluster Templates

Creating virtual cluster templates is similar to creating apps. Click Templates and then Virtual Clusters, as shown below:

Virtual cluster templates

In the screenshot, you can see two templates that are preinstalled in every Loft instance: Virtual Cluster Pro Template and Virtual Cluster Pro Template (Isolated). Click the Add Virtual Cluster Template button to continue.

Then, in the Definition tab, enter the name of the template and the Kubernetes distribution you want to use:

Virtual cluster template Definition tab

Note that there is also a field called Virtual Cluster Version, where you can specify which version of vCluster (and therefore Kubernetes) you want to use. Leave the field blank to accept the most recent version, and click the Apps tab.

Virtual cluster templates allow you to build a full-blown app stack. The image below shows an example using Prometheus-Grafana for observability and Cert Manager for certificate management:

Virtual cluster template Apps tab

You can install each one in a different namespace within the virtual cluster, assign permissions, customize settings, and more. To learn more about the rest of the options available to configure virtual cluster templates, refer to the documentation.

That said, for this example, just add my-saas-app, as shown below:

SaaS app

When you’re ready, click the Save Changes button to finish. This will take you back to the previous screen, where the new template will now be listed:

Virtual cluster templates screen

#Testing Your Virtual Template

Now that you’ve created the virtual cluster template, it’s time to test that everything works as expected.

Click Virtual Clusters at the top of the side menu, and then Create Virtual Cluster:

Create a new virtual cluster

Select the newly created virtual cluster template, enter a name for the virtual cluster, and click Create to continue:

Enter the test virtual cluster

Wait for the virtual cluster creation process to finish and click saas-app-test. Upon entering the virtual cluster, you’ll see several tabs where you can review namespaces, pods, apps, deployments, services, events, and more:

Inside test virtual cluster

Although you can verify that everything works as it should from this screen, it doesn’t hurt to go to the console and check the deployment.

If you use minikube, you can run minikube service list to list the cluster services:

$ minikube service list
|             NAMESPACE              |                   NAME                   | TARGET PORT  |            URL            |
| default                            | hello-minikube                           |         8080 | |
| default                            | kubernetes                               | No node port |                           |
| kube-system                        | kube-dns                                 | No node port |                           |
| loft-saas-tutorial-v-saas-app-test | kube-dns-x-kube-system-x-saas-app-test   | No node port |                           |
| loft-saas-tutorial-v-saas-app-test | my-app-service-x-default-x-saas-app-test |         8080 | | <--- saas-app
| loft-saas-tutorial-v-saas-app-test | saas-app-test                            | No node port |                           |
| loft-saas-tutorial-v-saas-app-test | saas-app-test-headless                   | No node port |                           |
| loft-saas-tutorial-v-saas-app-test | saas-app-test-node-minikube              | No node port |                           |
| loft                               | loft                                     | No node port |                           |
| loft                               | loft-apiservice                          | No node port |                           |
| loft                               | loft-apiservice-agent                    | No node port |                           |
| loft                               | loft-ingress-wakeup-agent                | No node port |                           |
| loft                               | loft-loadbalancer                        | https/443    | |
| loft                               | loft-webhook-agent                       | No node port |                           |

In the output above, you can see a clear difference between services deployed directly on the Kubernetes host (such as hello-minikube) and those deployed using Loft’s vCluster. If you click the external URL of the SaaS app, you’ll see the following screen, confirming that the deployment was successful:

SaaS app Nginx screen - Image Credit: Author

#Deploying Virtual Clusters Using API Calls

Up to this point, you were learning how to deploy virtual clusters that automatically deploy your SaaS app. You’ll now take the process one step further using API calls.

In addition to creating virtual clusters using the UI, you can do so using the Loft CLI and even kubectl. However, the premise of this tutorial is to teach you how to provision separate SaaS instances using the Loft API.

You can do that using a command like this:

curl -s -X POST --insecure \
    "https://$LOFT_DOMAIN/kubernetes/management/apis/" \
    --data-binary "$(cat vcluster-instance.yaml)" \
    -H "Content-Type: application/yaml" \
    -H "Authorization: Bearer $ACCESS_KEY"

Here, LOFT_DOMAIN is the domain assigned to your Loft instance. This domain was shown in the console when you ran loft start, but you can also review it by clicking Admin in the UI and checking Loft’s configuration:

Loft domain - Image Credit: Author

Toward the end of the second line of the command, you can see this:


Here, loft-p-saas-tutorial is the Kubernetes namespace name of the project, used to point the API call to the saas-tutorial project.

In the third line, vcluster-instance.yaml is the name of the Kubernetes manifest that will be passed to the Loft API. For this example, you will use:

kind: VirtualClusterInstance
  creationTimestamp: null
  generateName: saas-instance-
  namespace: loft-p-saas-tutorial
  clusterRef: {}
    user: admin
    team: loft-admins
    name: saas-app-template
status: {}

In the Loft API reference, you’ll find detailed information about the arguments you can include in this manifest. However, the following are worth highlighting:

  • generateName is an optional argument that tells Loft to generate a random virtual cluster name preceded by a prefix of your choice
  • namespace is the Kubernetes namespace corresponding to the project where you want to deploy the virtual cluster
  • user and team are the Loft user and team for this project
  • is the name of the virtual cluster template that will be used

Regarding authentication, ACCESS_KEY is an access token that you can generate from the UI.

So, once you have LOFT_DOMAIN and ACCESS_KEY, you could create a new virtual cluster within the saas-tutorial project that deploys my-saas-app automatically using a command similar to this:

export LOFT_DOMAIN=""
export ACCESS_KEY="xxxx"
curl -s -X POST --insecure \
    "https://$LOFT_DOMAIN/kubernetes/management/apis/" \
    --data-binary "$(cat vcluster-template.yaml)" \
    -H "Content-Type: application/yaml" \
    -H "Authorization: Bearer $ACCESS_KEY"

Go ahead and try it a few times.

If you now go to the UI, you will see something similar to the following:

Separate SaaS instances

That’s it! You deployed separate instances of your SaaS software with each API call. The possibilities of this approach are endless.

With the knowledge acquired, your development team could create a secure RESTful API for your SaaS solution using Python, Node.js, PHP, or any language or framework of their choice. They can design a microservice to deploy separate virtual clusters running your SaaS environments or whatever applications you need in your Kubernetes cluster.

Simply put, once you set up your projects, apps, and virtual cluster templates in Loft, you can embrace an API-first approach to create amazing solutions.


This tutorial began by highlighting some of the challenges associated with the multitenancy approach. Let’s review those pain points again from the perspective of what you learned in the article:

  • Tenants cannot use CRDs: Solved, since the virtual cluster overcomes this limitation by deploying a fully functional standalone virtual Kubernetes cluster.
  • Tenants cannot install Helm charts that use RBAC: Also solved, for the same reasons.
  • Tenants are limited to the version of Kubernetes used by the host: Solved, since you can specify the Kubernetes version in the virtual cluster template (with the Virtual Cluster Version field). Furthermore, you can even choose which distribution to use (Kubernetes, K3s, and so on).
  • User management: Through the Loft UI, you can create users and groups and apply the rules you consider appropriate.
  • Resource sharing: By editing values.yaml of the virtual cluster Helm chart, you can assign the resources you deem necessary for each virtual cluster template.
  • Security: Through the Loft UI, you can set permissions for specific projects, spaces, virtual clusters, and more.

This is just a fraction of what your organization can achieve with virtual Kubernetes clusters. Unleash your team’s full potential with Loft’s vCluster! Experience seamless, scalable virtual Kubernetes environments.

Sign up for our newsletter

Be the first to know about new features, announcements and industry insights.