Deploy a Node.js Application in SAP BTP, Kyma runtime
Build a basic Node.js application into OCI image and push it into Docker registry. Besides, describe the corresponding Kubernetes objects for the application. Based on the above, deploy the application into SAP BTP, Kyma runtime.
Overview
You will learn
- How to build Application to OCI Image
- How to push OCI image to Docker Hub
- How to describe Kubernetes objects for web application
- How to deploy application into Kyma runtime
Prerequisites
Prerequisites
- You have a Kyma runtime environment on SAP Business Technology Platform (BTP) and the relevant command line tools. If not, please follow the tutorials Enable SAP BTP, Kyma runtime and Install the Kubernetes Command Line Tool.
- You have installed Docker.
- You have Docker Hub account.
- You have finished the tutorial Create a Basic Node.js Application with Express Generator.
Steps
Open your subaccount in SAP BTP cockpit. Make sure you’ve already enabled SAP BTP, Kyma runtime on your cluster.
In order to run your code on Kyma Runtime (or on any Kubernetes-based platform), you need to provide an OCI image (aka Docker image) for your application. While you are in principle free to choose your image building tool, we recommend using Cloud Native Buildpacks (CNB).
The command-line tool pack supports providing a buildpack and your local source code and creating an OCI image from it. We are working on a process to provide recommended and supported buildpacks. In the meantime, you can use the community-supported Paketo Buildpacks.
1. Install command-line tool pack: Install Pack
For example (macOS):
brew install buildpacks/tap/packWhen we speak about repository name, we mean the combination of account and repo name that is usual with Docker Hub: <docker-hub-account>/<repo-name>. An example would be tiaxu/multitenant-kyma-backend.
As you can only create one private repository in a free Docker hub account, Docker images stored in Docker hub will have different tag names so that they can be stored under one repository. Thus, addressing an image will include the tag name:<docker-hub-account>/<repo-name>:<tag-name>. An example would be tiaxu/multitenant-kyma-backend:v1.
2. In the directory kyma-multitenant-node, build the image for the approuter app from source, for example:
pack build <docker-hub-account>/multitenant-kyma-backend:v1 --builder paketobuildpacks/builder-jammy-full1. Log in to Docker using this command:
docker login -u <docker-id> -p <password>2. Push the local image into the Docker Hub:
docker push <docker-hub-account>/multitenant-kyma-backend:v1For more details, see the Kubernetes documentation.
Then you are ready to deploy it into the Kubernetes cluster with Kyma runtime.
1. Select the Link to dashboard to open Kyma dashboard.

2. Create a new namespace through Kyma dashboard or kubectl CLI, for example, called multitenancy-ns:

3. Enable Istio Sidecar Proxy Injection
Enabling Istio sidecar proxy injection for a namespace allows istiod to watch all Pod creation operations in this namespace and automatically inject newly created Pods with an Istio sidecar proxy.
Switch the toggle to enable Istio sidecar proxy injection. Click Create to finish namespace creation.

For more details, refer to the Enable Istio Sidecar Proxy Injection
Since the OCI image is stored in your Docker hub, you need to provide the access information to your Kyma cluster that you can pull the images from those repositories, replace the placeholder values according to your account:
kubectl -n multitenancy-ns create secret docker-registry registry-secret --docker-server=https://index.docker.io/v1/ --docker-username=<docker-id> --docker-password=<password> --docker-email=<email>Therefore, all deployment files contain an imagePullSecret entry, which should be set to registry-secret.
imagePullSecrets:
- name: registry-secret # replace with your own registry secretBased on the previous preparation steps, you can define the description file for deployment.
In the root directory multitenancy-kyma-tutorial, create a new YAML file called k8s-deployment-backend.yaml with the following content:
---
apiVersion: gateway.kyma-project.io/v2
kind: APIRule
metadata:
labels:
app: kyma-multitenant-node-multitenancy
release: multitenancy
name: kyma-multitenant-node-multitenancy
spec:
gateway: kyma-system/kyma-gateway
hosts:
- kyma-multitenant-node-multitenancy
rules:
- path: /*
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"]
noAuth: true
service:
name: kyma-multitenant-node-multitenancy
port: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: kyma-multitenant-node-multitenancy
release: multitenancy
name: kyma-multitenant-node-multitenancy
spec:
replicas: 1
selector:
matchLabels:
app: kyma-multitenant-node-multitenancy
release: multitenancy
template:
metadata:
labels:
app: kyma-multitenant-node-multitenancy
release: multitenancy
sidecar.istio.io/inject: "true" # Enable Istio sidecar injection on Deployment and all Pods
spec:
imagePullSecrets:
- name: registry-secret # replace with your own registry secret
containers:
- env:
- name: PORT
value: "8080"
- name: TMPDIR
value: /tmp
- name: BP_NODE_OPTIMIZE_MEMORY
value: "false"
image: <docker-hub-account>/multitenant-kyma-backend:v1 # replace with your Docker Hub account name
name: kyma-multitenant-node-multitenancy
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
startupProbe:
httpGet:
path: /
port: http
failureThreshold: 15
periodSeconds: 2
resources:
limits:
cpu: 100m
memory: 256M
requests:
cpu: 100m
memory: 256M
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
runAsNonRoot: true
readOnlyRootFilesystem: false
volumeMounts:
- mountPath: /tmp
name: tmp
volumes:
- emptyDir: {}
name: tmp
---
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: kyma-multitenant-node-multitenancy
release: multitenancy
name: kyma-multitenant-node-multitenancy
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
app: kyma-multitenant-node-multitenancy
release: multitenancy
status:
loadBalancer: {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
creationTimestamp: null
labels:
release: multitenancy
name: multitenancy
spec:
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: istio-system
podSelector:
matchLabels:
app: istio-ingressgateway
podSelector:
matchLabels:
release: multitenancy
policyTypes:
- IngressReplace the placeholders with the values that you got in the previous steps.
Deploy the Node.js application by executing this command under the root directory multitenancy-kyma-tutorial:
kubectl -n multitenancy-ns apply -f k8s-deployment-backend.yamlLaunch Kyma dashboard from SAP BTP cockpit, then navigate to the multitenancy-ns namespace.
Go to Workloads, and then select Deployments. You will see deployment of kyma-multitenant-node-multitenancy displayed, with its Pods status shown in green. At this point, your application has been deployed successfully.

1. Find the URL address of your application in Kyma dashboard:

2. Access it in the browser, then the application will return the message “Hello World!”.
You can find the final Node.js project from repository: here.
Resources
Discussion
Share feedback on this tutorial or join the conversation in SAP Community.