SAP Build Apps pro and community edition is a build-apps platforms featuring Composer Pro - a browser-based application designer with an integrated build service. This brief is to explain how to make use of SAP Build Apps build service and have your SAP Build Apps web applications deployed directly to SAP BTP, Kyma runtime. With little effort. That is leveraging k8s volumes and a public SAP Approuter image deployed to a kyma cluster and acting as a multi-tenant web application server. |
Q. What have I done? A. In a nutshell, I extended the aforementioned SAP build Apps custom deployment pattern to SAP BTP, Kyma runtime. And that, without any reliance on additional BTP services. I opted for a native k8s/kyma volume binding mechansim with SAP Approuter acting as an application server. Once downloaded from the SAP Build Apps build service, a static web app is "injected" directly into a running SAP approuter context via a standard k8s volume binding mechanism. |
initContainers:
- name: install
image: alpine/curl
securityContext:
runAsUser: 1337
command:
- sh
- -c
- >-
curl -H 'Authorization: token {{ $token }}' -H 'Accept: application/vnd.github.v4.raw' -o /app/resources-dir/{{ $webappname }} -L {{ $image }}{{ $webappname }} &&
unzip /app/resources-dir/{{ $webappname }} -d /app/resources-dir
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
volumes:
- name: resources-dir
emptyDir:
medium: "Memory"
sizeLimit: 50Mi
clusterDomain:
gateway:
ttlDaysAfterFinished: 0
services:
app:
name: faas-appgyver
appgyver:
webappname: app-*****_web_build-****.zip
token: ghp_*******************************
webapppath: https://github.com/api/v3/repos/<>/<>/contents/appgyver/
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: resources-dir
labels:
{{- include "app.labels" . | nindent 4 }}
app: {{ .Values.services.app.name }}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: 'files'
volumeMode: Filesystem
{{- $deployment := .Values.services | default dict }}
{{- $image := $deployment.appgyver.webapppath | default "/" }}
{{- $webappname := $deployment.appgyver.webappname | default "app-*****_web_build-****.zip" }}
{{- $token := $deployment.appgyver.token | default "token" }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Values.services.app.name }}
labels:
{{- include "app.labels" . | nindent 4 }}
app: {{ .Values.services.app.name }}
spec:
ttlSecondsAfterFinished: 100 ## {{ mul .Values.ttlDaysAfterFinished 24 60 60 }}
parallelism: 1
completions: 1
manualSelector: false
template:
metadata:
labels:
{{- include "app.selectorLabels" . | nindent 8 }}
sidecar.istio.io/inject: 'false'
spec:
restartPolicy: OnFailure
containers:
- image: busybox
name: busybox
command: ['sh', '-c', 'echo The job is running! && sleep 1']
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
initContainers:
- name: install000
image: alpine
command:
- sh
- -c
- >-
chmod -R 777 /app && ls -lh -d /app/resources-dir
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
- name: install001
image: alpine/curl
command:
- sh
- -c
- >-
curl -H 'Authorization: token {{ $token }}' -H 'Accept: application/vnd.github.v4.raw' -o /app/resources-dir/{{ $webappname }} -L {{ $image }}{{ $webappname }} &&
ls -l app/resources-dir &&
unzip -o /app/resources-dir/{{ $webappname }} -d /app/resources-dir &&
ls -l /app/resources-dir &&
ls -lh -d /app/resources-dir
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
volumes:
- name: resources-dir
persistentVolumeClaim:
claimName: resources-dir
Your virtual Musee du Louvre visit and mug painting powered by DALL·E: or, eventually, an excursion (if ever), to Mars: Last but not least, why not having a business application leveraging SAP HANA and SAP Analytics Cloud as well. All on Kyma folks. |
This is a SAP Fiori Launchpad. embedded into MS Teams as Teams app, where each tile is a SAP Build web-app running on Kyma |
SAP Build Apps can produce ready-to-deploy MTAR files which can be deployed to a BTP sub-account's HTML5 repository. Headline:
|
SAP Build Apps can produce ready-to-deploy static web applications content packaged as ZIP files. Headlines:
|
Subsequently, static web-app ZIP files can be:
|
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.services.app.xsapp }}
data:
xs-app.json: |-
{
"welcomeFile": "index.html",
"authenticationMethod": "route",
"routes": [
{
"source": "^/user-api(.*)",
"target": "$1",
"service": "sap-approuter-userapi",
"authenticationType": "xsuaa",
"scope": "$XSAPPNAME.Admin"
}
,
{
"source": "^/dynamic_dest/([^/]+)/(.*)$",
"target": "$2",
"authenticationType": "xsuaa",
"preferLocal": true,
"destination": "$1"
}
,
{
"source": "/(.*)",
"authenticationType": "xsuaa",
"scope": "$XSAPPNAME.User",
"localDir": "resources-dir",
"cacheControl": "public, max-age=1000,must-revalidate"
}
]
}
{{- $deployment := .Values.services | default dict }}
{{- $image := $deployment.appgyver.webapppath | default "/" }}
{{- $webappname := $deployment.appgyver.webappname | default "app-*****_web_build-****.zip" }}
{{- $token := $deployment.appgyver.token | default "token" }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.services.app.name }}
labels:
{{- include "app.labels" . | nindent 4 }}
app: {{ .Values.services.app.name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "app.selectorLabels" $ | nindent 6 }}
template:
metadata:
labels:
{{- include "app.selectorLabels" . | nindent 8 }}
spec:
{{- if (include "app.ha" .) }}
topologySpreadConstraints:
{{- range $constraint := .Values.availability.topologySpreadConstraints }}
- maxSkew: {{ $constraint.maxSkew }}
topologyKey: {{ $constraint.topologyKey }}
whenUnsatisfiable: {{ $constraint.whenUnsatisfiable }}
labelSelector:
matchLabels:
{{- include "app.selectorLabels" $ | nindent 12 }}
{{- end }}
{{- end }}
containers:
- image: "{{ .Values.services.app.image.dockerID }}/{{ .Values.services.app.image.repository }}:{{ .Values.services.app.image.tag }}"
name: {{ .Values.services.app.name }}
imagePullPolicy: {{ .Values.services.app.image.pullPolicy }}
resources:
limits:
memory: 512Mi
cpu: "1"
requests:
memory: 128Mi
cpu: "0.1"
ports:
- name: http
containerPort: {{ .Values.services.app.image.port }}
env:
- name: SERVICE_BINDING_ROOT
value: /bindings
- name: PORT
value: '{{ .Values.services.app.image.port }}'
- name: XS_APP_LOG_LEVEL
value: debug
- name: DEBUG
value: '*' ## xssec:* ### https://www.npmjs.com/package/@sap/xssec
- name: COOKIES
value: "{ \"SameSite\":\"None\" }" ### https://me.sap.com/notes/0002953730
- name: SEND_XFRAMEOPTIONS
value: 'false' ###https://www.npmjs.com/package/@sap/approuter#x-frame-options-configuration
- name: ENABLE_X_FORWARDED_HOST_VALIDATION
value: 'true' ### https://www.npmjs.com/package/@sap/approuter#configurations
- name: INCOMING_CONNECTION_TIMEOUT
value: '1800000' # 180 seconds, the default value is 120 seconds
- name: CORS
value: |-
[
{
"uriPattern": "^(.*)$",
"allowedOrigin": [
{"host":"*", "protocol":"https"}
],
"allowedMethods": ["GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE"],
"allowedHeaders": ["Origin", "Accept", "X-Requested-With", "Content-Type", "Access-Control-Request-Method", "Access-Control-Request-Headers", "Authorization", "X-Sap-Cid", "X-Csrf-Token", "Accept-Language"],
"exposeHeaders": ["Accept", "Authorization", "X-Requested-With", "X-Sap-Cid", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", "X-Csrf-Token", "Content-Type"]
}
]
envFrom:
- configMapRef:
name: {{ .Values.services.app.name }}
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
- name: xs-app
mountPath: "/app/xs-app.json"
subPath: "xs-app.json"
readOnly: true
- name: resources
mountPath: "/app/resources-dir/default.html" ##"/app/resources/default.html"
subPath: "default.html"
readOnly: true
- name: faas-uaa
mountPath: "/bindings/faas-uaa"
readOnly: true
- name: faas-dest
mountPath: "/bindings/faas-dest"
readOnly: true
initContainers:
- name: install
image: alpine/curl
securityContext:
runAsUser: 1337
command:
- sh
- -c
- >-
curl -H 'Authorization: token {{ $token }}' -H 'Accept: application/vnd.github.v4.raw' -o /app/resources-dir/{{ $webappname }} -L {{ $image }}{{ $webappname }} &&
ls -l app/resources-dir &&
unzip /app/resources-dir/{{ $webappname }} -d /app/resources-dir &&
ls -l /app/resources-dir &&
ls -lh -d /app/resources-dir
volumeMounts:
- name: resources-dir
mountPath: /app/resources-dir
subPath: resources-dir
volumes:
- name: resources-dir
emptyDir:
medium: "Memory"
sizeLimit: 70Mi
- name: xs-app
configMap:
name: {{ .Values.services.app.xsapp }}
- name: resources
configMap:
name: {{ .Values.services.app.resources }}
- name: faas-uaa
secret:
secretName: {{ .Values.services.uaa.bindingSecretName }}
- name: faas-dest
secret:
secretName: {{ .Values.services.dest.bindingSecretName }}
Per aspera ad astra. Who am I?You can follow me in SAP Community: piotr.tesny Pre-requisites:
Disclaimer:
Additional resources
|
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
26 | |
24 | |
21 | |
13 | |
11 | |
9 | |
9 | |
8 | |
8 | |
8 |