Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
quovadis
Product and Topic Expert
Product and Topic Expert














Serverless architecture

This brief is to demonstrate how one can leverage selected SAP BTP Kyma runtime serverless features.

This instalment covers:

  •  how to override a base function image










Requirements and Disclaimers:







Sample code:




Putting it all together.


SAP BTP, Kyma runtime is SAP's fully managed commercial kubernetes offering, part of SAP Business Technology Platform. It is often bundled with SAP Commerce Cloud and nowadays is becoming an extensibility runtime of choice.

Kyma brings additional modules on top of a kubernetes cluster. And serverless manager is one of them.

Good to know:

  • The serverless features described in this and following instalments can be used with both unmanaged OS Kyma on Gardener and SAP-managed SAP BTP, Kyma runtime.


Serverless Architecture


The serveless architecture is far from being trivial. Please study the diagram carefully.


Next, let's have a look at the Function's specification.


Seemingly, one of the coolest features with Kyma serverless CRD is the ability to override the base runtime image of a function.


This can be really useful when the default runtime image is just not good enough to accommodate some specific runtime dependencies.


However, please mind the gap. The kyma default base runtime function images are Alpine based. And Alpine based nodejs images have an extremely low count of security vulnerabilities;



Override function base image


For the sake of this brief, let's try it out with the nodejs16 functions. However, same approach is valid with any other supported serverless runtime, for instance with python 3.9.

In order to replace a default base image of a nodejs16 function we should try to understand how kyma does it.

Let's have a look at a Dockerfile definition used by kyma itself to create a function base image, namely:
# image base on 16.19.0-alpine3.17
FROM node@sha256:e427ffd1ba7915ca8d8aeba45806ef3f1f1e6b65ce152b363645cd7428f8d75a


ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
ENV npm_config_cache /tmp/

RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/app/lib
WORKDIR /usr/src/app

COPY package.json /usr/src/app/
RUN npm install && npm cache clean --force
COPY lib /usr/src/app/lib

COPY server.js /usr/src/app/server.js

CMD ["npm", "start"]

EXPOSE 8888

The build of the above Dockerfile will result in the following stock image, that eventually will be used in the function kaniko build
eu.gcr.io/kyma-project/function-runtime-nodejs16:v20230117-d8ab8401

Good to know:

  • The docker files used in the function build are stored as config maps in a kyma cluster namespaces. Goto your cluster to look them up.


Building a custom image.


In order the build a custom image first you need to clone the project kyma github repository:
gh repo clone kyma-project/kyma
cd components/function-runtimes/nodejs16/
...............
add your Dockerfile, build the custom image and push it
to an internet facing docker repository
...............
cp Dockerfile Dockerfile.custom.nodejs16
nano Dockerfile.custom.nodejs16
...............
edit your Dockerfile.custom.nodejs16 then save it
and build your custom image
...............
docker build --platform amd64 -t <docker_id>/<docker_repo>:bullseye-slim16 -f ./Dockerfile.custom.nodejs16 .

You also need to make a decision about a new base nodejs16 image. That's an important decision as you are entirely liable/responsible for this choice and the custom image that will be built based upon it.

For the sake of this brief I have picked a public node:16.19.0-bullseye-slim as my new nodejs16 base image.

Next, you can create a custom function base image using a custom Dockerfile.custom.nodejs16 definition.

Last but not least, you shall need to publish the image to a public and internet facing docker repository.

For instance, let's say the new nodejs base image is node:16.19.0-bullseye-slim and that we are going to add a bunch of linux libraries to accommodate for any specific runtime dependencies, as follows:
FROM node:16.19.0-bullseye-slim


ARG NODE_ENV
ENV NODE_ENV $NODE_ENV
ENV npm_config_cache /tmp/

RUN mkdir -p /usr/src/app
RUN mkdir -p /usr/src/app/lib
WORKDIR /usr/src/app

COPY package.json /usr/src/app/
RUN npm install && npm cache clean --force

RUN apt-get update
RUN apt-get install -y openssl python make g++

COPY lib /usr/src/app/lib

COPY server.js /usr/src/app/server.js

CMD ["npm", "start"]

EXPOSE 8888

Let's build and then publish the custom image:

  • docker build --platform amd64 -t <docker_id>/<docker_repo>:bullseye-slim16 -f ./Dockerfile.custom.nodejs16 .


[+] Building 2.4s (16/16) FINISHED                                                                                                                                                                                          

=> [ 1/10] FROM docker.io/library/node:16.19.0-bullseye-slim@sha256:cfb2b5e2b39f341056ac624d32fae00ba0ab94145364111b7edfd9db703526e0 0.0s
=> CACHED [ 2/10] RUN mkdir -p /usr/src/app 0.0s
=> CACHED [ 3/10] RUN mkdir -p /usr/src/app/lib 0.0s
=> CACHED [ 4/10] WORKDIR /usr/src/app 0.0s
=> CACHED [ 5/10] COPY package.json /usr/src/app/ 0.0s
=> CACHED [ 6/10] RUN npm install && npm cache clean --force 0.0s
=> CACHED [ 7/10] RUN apt-get update 0.0s
=> CACHED [ 8/10] RUN apt-get install -y openssl python make g++ 0.0s
=> CACHED [ 9/10] COPY lib /usr/src/app/lib 0.0s
=> CACHED [10/10] COPY server.js /usr/src/app/server.js 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => naming to docker.io/<docker_id>/<docker_repo>:bullseye-slim16

Publishing the custom image:

  • docker push <docker_id>/<docker_repo>:bullseye-slim16


Eventually, this custom image can be used with kyma serverless nodejs16 functions definitions, for instance:
apiVersion: serverless.kyma-project.io/v1alpha2
kind: Function
metadata:
name: runtime-image-override
labels:
app.kubernetes.io/name: runtime-image-override
annotations: {}
namespace: default
spec:
runtime: nodejs16
source:
inline:
source: |-
module.exports = {
main: async function (event, context) {
const message = `Hello World`
+ ` from the Kyma Function ${context["function-name"]}`
+ ` running on ${context.runtime}!`;
console.log(message);
return message;
}
}
runtimeImageOverride: <docker_id>/<docker_repo>:bullseye-slim16

Thus all is needed is adding spec.runtimeImageOverride to the function definition with the name of the custom image and applying the new definition.

Good to know:

  • in order to force the image change with an existing function the source code of this function may need to be touched/edited as well as to trigger the function build process.

  • unsupported base images with their Dockerfiles for either nodejs16 or nodejs14 can be looked up here.

  • a more thorough sample code that demonstrates  SAP HANA Cloud official nodejs driver from a function is available in this gist.


Conclusion


In the next instalment of this series I will demonstrate how to use standard sap libraries to access secrets mounted as volumes.

To help you get started there is a serverless code sample here.

Good to know:

Visual Studio Code

I hope you have enjoyed reading the blog post. Feel free to provide feedback in the comments section below.

 




SAP Community: https://community.sap.com/

SAP Community Topic Page link: https://community.sap.com/topics/kyma

SAP Community Q&A Tags:
Kyma Open Source: https://answers.sap.com/tags/2936b97d-6a90-4cd8-b635-0e51441611eb
SAP BTP, Kyma runtime: https://answers.sap.com/tags/73554900100800003012

Follow me in SAP Community: piotr.tesny