Fast Prototyping in SAP BTP, Kyma Runtime Using App Push
Deploy a containerized application to SAP BTP, Kyma runtime in a single CLI command using kyma app push, with no Dockerfile or external container registry needed.
Overview
You will learn
- How to go from source code to a running, externally accessible application on Kyma runtime in a single command
- How to iterate quickly on a prototype without writing Kubernetes manifests, Dockerfiles, or configuring a container registry
- How to evolve a local prototype into an automated GitHub Actions CD pipeline
Prerequisites
Prerequisites
- SAP BTP, Kyma runtime enabled
- Kyma CLI installed
- kubectl configured to kubeconfig downloaded from SAP BTP, Kyma runtime
- Git installed
- Add the Istio, API Gateway, and SAP BTP Operator Kyma modules, if not added by default
- Add the Docker Registry community module
Steps
For this tutorial, we use a Spring Boot application that exposes a REST API for managing movies, storing data in BTP Object Store.
Intro
In this tutorial, you will deploy a Spring Boot REST API for managing movies, backed by SAP BTP Object Store. The kyma app push command builds the application using Cloud Native Buildpacks (no Dockerfile needed), pushes the image to the in-cluster registry, and creates all required Kubernetes resources in one step.
Go to the kyma-runtime-samples repository and use the green Code button to choose one of the options to download the code locally, or simply run the following command using your CLI at your desired folder location:
Shell/Bashgit clone https://github.com/SAP-samples/kyma-runtime-samples
Open the
movies-restdirectory in your desired editor.Explore the content of the sample.
The directory contains a Maven-based Spring Boot application with REST endpoints for CRUD operations on movie data, backed by SAP BTP Object Store. A
.envfile provides JVM memory tuning required to fit within the default container memory limit.NOTE: Object Store is used here for the sake of simplicity. For applications with structured, relational data, use a proper database such as SAP HANA Cloud or PostgreSQL.
From your subaccount overview in the SAP BTP cockpit, go to Entitlements and choose Edit.
Choose Add Service Plans and search for Object Store.
Select the standard plan and choose Add 1 Service Plan.
Choose Save.
Create the
devnamespace and enable Istio:Shell/Bashkubectl create namespace devNOTE: Namespaces separate objects inside a Kubernetes cluster. Choosing a different namespace requires adjustments to the provided samples.
Create the Object Store ServiceInstance and ServiceBinding:
Shell/Bashkubectl -n dev apply -f - <<EOF apiVersion: services.cloud.sap.com/v1 kind: ServiceInstance metadata: name: object-store-instance spec: serviceOfferingName: objectstore servicePlanName: standard --- apiVersion: services.cloud.sap.com/v1 kind: ServiceBinding metadata: name: object-store-binding spec: serviceInstanceName: object-store-instance EOFWait for the binding to become ready:
Shell/Bashkubectl -n dev get servicebinding object-store-binding -wOnce the
STATUScolumn showsReady, a Kubernetes Secret namedobject-store-bindingis created in the namespace with the Object Store credentials.
From the
movies-restdirectory, run the following command to build, push, and deploy the application:Shell/Bashkyma app push \ --name movies-rest \ --namespace dev \ --code-path . \ --container-port 8080 \ --expose \ --istio-inject=true \ --mount-service-binding-secret object-store-binding \ --env-from-file .envWhat happens under the hood:
- Source code is built into a container image using Cloud Native Buildpacks (Paketo). No Dockerfile is required — Buildpacks detect
pom.xmland automatically build a Java application with the correct JDK. - The image is pushed to the in-cluster Docker Registry.
- A Deployment, Service, and APIRule are created.
- The Object Store binding secret is mounted at
/bindings/secret-object-store-binding, andSERVICE_BINDING_ROOT=/bindingsis set automatically.
NOTE: The same approach works for any language supported by Cloud Native Buildpacks — Node.js, Go, Python, .NET, and more.
- Source code is built into a container image using Cloud Native Buildpacks (Paketo). No Dockerfile is required — Buildpacks detect
Once
kyma app pushcompletes, it prints the app URL:Shell/BashThe movies-rest app is available under the movies-rest.<CLUSTER_DOMAIN>.kyma.ondemand.com'TIP: In quiet mode, the app URL is the only output — useful for capturing it in scripts:
Shell/BashAPP_URL=$(kyma app push ... --quiet) echo $APP_URLOpen the interactive Swagger UI in your browser at
https://<APP_URL>/swagger-ui.htmland test the CRUD operations on the movies endpoint.Use the Swagger UI to test the CRUD operations on the movies endpoint.
NOTE: The OpenAPI specification is also available at
https://movies-rest.<CLUSTER_DOMAIN>/v3/api-docs.
Once your prototype stabilizes, you can automate deployments on every push to your repository using GitHub Actions.
Push your application code to a GitHub repository, for example
https://github.com/<YOUR-ORG>/movies-rest.Authorize the repository’s GitHub Actions workflows to deploy to your Kyma cluster:
Shell/Bashkyma alpha authorize repository \ --client-id my-client-id-for-gh-action \ --cluster-wide \ --clusterrole edit \ --repository <YOUR-ORG>/movies-restThis command configures your Kyma cluster to trust GitHub OIDC tokens issued for the specified repository. The workflow will obtain cluster access using a short-lived GitHub OIDC token — no long-lived credentials are stored. The only values you need to keep as secrets are the API server URL and CA certificate, which are connection details rather than credentials.
NOTE: The
--clusterrole editflag is used here for simplicity. In production, choose the most restrictive ClusterRole that satisfies your workflow’s needs. You can also limit authorization to a specific workflow, branch, or environment using--require-claim. Runkyma alpha authorize repository --helpfor details.Add the cluster connection details as GitHub Actions secrets. Run the following commands locally to get the values:
Shell/Bashkubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' kubectl config view --minify --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}'In your GitHub repository, go to Settings > Secrets and variables > Actions > New repository secret and add:
SERVER— the API server URL returned by the first commandCA_CRT— the base64-encoded CA certificate returned by the second command
Create the following GitHub Actions workflow file in your repository at
.github/workflows/deploy.yaml:YAMLname: Deploy permissions: id-token: write contents: read on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Kyma CLI uses: kyma-project/setup-kyma-cli@v1.1.0 - name: Get kubeconfig id: oidc uses: kyma-project/setup-kyma-cli/kubeconfig@v1.1.0 with: audience: "my-client-id-for-gh-action" api-server-url: "${{ secrets.SERVER }}" ca-crt: "${{ secrets.CA_CRT }}" id-token-auto-refresh: "true" - name: Set short SHA run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV - uses: kyma-project/setup-kyma-cli/app-push@v1.1.0 with: name: movies-rest namespace: dev code-path: . build-tag: "${{ env.SHORT_SHA }}" container-port: "8080" expose: "true" istio-inject: "true" mount-service-binding-secret: object-store-binding kubeconfig: "${{ steps.oidc.outputs.kubeconfig }}" env-from-file: .env append-output-path: /swagger-ui.htmlEvery push to the
mainbranch now triggers a fresh build and deploy. No local tooling is required after the initial setup.
Resources
Discussion
Share feedback on this tutorial or join the conversation in SAP Community.