From c67e072a0dc57e6fe4e96101cab88d2cf50f0f14 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Mon, 4 May 2026 12:05:58 +0200 Subject: [PATCH 1/9] Single container app tutorials --- .../01-40-fast-prototyping-app-push.md | 424 ++++++++++++++++++ ...0-fast-prototyping-serverless-functions.md | 103 +++++ examples/movies-api/pom.xml | 51 +++ .../java/com/example/movies/Application.java | 17 + .../main/java/com/example/movies/Movie.java | 20 + .../com/example/movies/MovieController.java | 85 ++++ .../com/example/movies/ObjectStoreConfig.java | 44 ++ .../src/main/resources/application.properties | 1 + 8 files changed, 745 insertions(+) create mode 100644 docs/user/tutorials/01-40-fast-prototyping-app-push.md create mode 100644 docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md create mode 100644 examples/movies-api/pom.xml create mode 100644 examples/movies-api/src/main/java/com/example/movies/Application.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/Movie.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/MovieController.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java create mode 100644 examples/movies-api/src/main/resources/application.properties diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md new file mode 100644 index 000000000..6aa8bc493 --- /dev/null +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -0,0 +1,424 @@ +# Fast Prototyping on SAP BTP Kyma: App Push + +This tutorial shows how to deploy a single-container application to SAP BTP Kyma runtime in one CLI command using `kyma app push`, then evolve it into an automated GitHub Actions CD pipeline. No YAML hand-crafting, no container registry setup, no CI/CD pipeline to configure upfront — just code → deploy → iterate. + +It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET), need BTP service bindings (e.g., Object Store), and want a clear path from local development to automated CD — all without writing a Dockerfile. + +> For lightweight event-driven workloads where you want zero container knowledge, see [Fast Prototyping With Serverless Functions](01-50-fast-prototyping-serverless-functions.md). + +## Prerequisites + +- [Kyma CLI](https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-cli?locale=en-US#install-kyma-cli) installed. +- The following [Kyma modules enabled](https://help.sap.com/docs/btp/sap-business-technology-platform/enable-and-disable-kyma-module#adding-a-kyma-module) on your runtime: + - **Istio** (enabled by default) — service mesh and networking + - **API Gateway** (enabled by default) — external exposure via APIRule + - **BTP Operator** (enabled by default) — manages BTP service instances and bindings + - **Docker Registry** ([community module](https://kyma-project.io/external-content/community-modules/docs/user/README.html#quick-install)) — in-cluster container registry for building and storing images (no external registry needed) +- Your SAP BTP subaccount must be **entitled to use the SAP Object Store service** (service plan `standard`). Add the entitlement in the BTP cockpit under *Entitlements* if not already assigned. + +## Step 1: Create Your App + +For this example, use a Spring Boot application that exposes a REST API for managing movies, storing data in BTP Object Store: + +```bash +mkdir my-prototype && cd my-prototype +``` + +Create the Maven project structure: + +```bash +mkdir -p src/main/java/com/example/movies +``` + +**pom.xml**: + +```xml + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.3.0 + + + com.example + movies + 1.0.0 + + + 21 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + com.sap.cloud.environment.servicebinding + java-sap-service-operator + 0.10.6 + + + software.amazon.awssdk + s3 + 2.25.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +``` + +**src/main/java/com/example/movies/Application.java**: + +```java +package com.example.movies; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info( + title = "Movies API", + version = "1.0.0", + description = "CRUD REST service for movies, backed by SAP BTP Object Store")) +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + +**src/main/java/com/example/movies/ObjectStoreConfig.java**: + +```java +package com.example.movies; + +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import java.net.URI; +import java.util.Map; + +@Configuration +public class ObjectStoreConfig { + + @Bean + public S3Client s3Client() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + + Map creds = binding.getCredentials(); + return S3Client.builder() + .region(Region.of((String) creds.get("region"))) + .endpointOverride(URI.create((String) creds.get("endpoint"))) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create( + (String) creds.get("access_key_id"), + (String) creds.get("secret_access_key")))) + .build(); + } + + @Bean + public String bucketName() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(); + return (String) binding.getCredentials().get("bucket"); + } +} +``` + +**src/main/java/com/example/movies/Movie.java**: + +```java +package com.example.movies; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Movie resource") +public record Movie( + @Schema(description = "Auto-generated ID", example = "1714900000000", accessMode = Schema.AccessMode.READ_ONLY) + String id, + @Schema(description = "Movie title", example = "Blade Runner") + String title, + @Schema(description = "Release year", example = "1982") + int year, + @Schema(description = "Director name", example = "Ridley Scott") + String director, + @Schema(description = "Rating out of 10", example = "8.1") + Double rating) { + public Movie withId(String newId) { + return new Movie(newId, title, year, director, rating); + } +} +``` + +**src/main/java/com/example/movies/MovieController.java**: + +```java +package com.example.movies; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/movies") +@Tag(name = "Movies", description = "CRUD operations for movie resources") +public class MovieController { + + private final S3Client s3; + private final String bucket; + private final ObjectMapper mapper = new ObjectMapper(); + + public MovieController(S3Client s3, String bucketName) { + this.s3 = s3; + this.bucket = bucketName; + } + + @GetMapping + @Operation(summary = "List all movies") + public List list() throws IOException { + ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + return response.contents().stream() + .map(obj -> getMovie(obj.key())) + .toList(); + } + + @GetMapping("/{id}") + @Operation(summary = "Get a movie by ID") + public Movie get(@PathVariable String id) { + return getMovie("movies/" + id + ".json"); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "Create a new movie") + public Movie create(@RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); + putMovie(saved); + return saved; + } + + @PutMapping("/{id}") + @Operation(summary = "Update an existing movie") + public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(id); + putMovie(saved); + return saved; + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete a movie") + public void delete(@PathVariable String id) { + s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + } + + private void putMovie(Movie movie) throws Exception { + byte[] json = mapper.writeValueAsBytes(movie); + s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") + .contentType("application/json"), RequestBody.fromBytes(json)); + } + + private Movie getMovie(String key) { + try { + byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + return mapper.readValue(data, Movie.class); + } catch (NoSuchKeyException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} +``` + +**src/main/resources/application.properties**: + +```properties +server.port=8080 +``` + +## Step 2: Create the BTP Object Store Service Instance and Binding + +Create the service instance and binding using the BTP Operator API (provided by the btp-manager module): + +```yaml +# service-instance.yaml +apiVersion: services.cloud.sap.com/v1 +kind: ServiceInstance +metadata: + name: object-store-instance + namespace: default +spec: + serviceOfferingName: objectstore + servicePlanName: standard +``` + +```yaml +# service-binding.yaml +apiVersion: services.cloud.sap.com/v1 +kind: ServiceBinding +metadata: + name: object-store-binding + namespace: default +spec: + serviceInstanceName: object-store-instance +``` + +Apply both resources: + +```bash +kubectl apply -f service-instance.yaml +kubectl apply -f service-binding.yaml +``` + +Wait for the binding to become ready: + +```bash +kubectl get servicebindings object-store-binding -w +``` + +Once the status shows `Ready: True`, a Kubernetes Secret named `object-store-binding` is created in the namespace with the Object Store credentials. + +## Step 3: Deploy + +One command builds, pushes, and deploys your app — and exposes it externally: + +```bash +kyma app push \ + --name my-prototype \ + --code-path . \ + --container-port 8080 \ + --expose \ + --istio-inject=true \ + --mount-service-binding-secret object-store-binding +``` + +What happens under the hood: +1. Source code is built into a container image using [Cloud Native Buildpacks](https://buildpacks.io/) (Paketo) +2. Image is pushed to the in-cluster docker-registry +3. A Deployment, Service, and APIRule are created +4. The BTP Object Store binding secret is mounted at `/bindings/secret-object-store-binding` +5. `SERVICE_BINDING_ROOT=/bindings` environment variable is set automatically + +> No Dockerfile required. Buildpacks detect `pom.xml` and automatically build a Java application with the correct JDK. The same approach works for Node.js, Go, Python, .NET, and more. + +## Step 4: Verify + +The command outputs the external URL of your app. Test the CRUD operations: + +```bash +# Health check +curl https:///health +# {"status":"UP"} + +# Create a movie +curl -X POST https:///movies \ + -H "Content-Type: application/json" \ + -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott"}' +# {"id":"1714900000000","title":"Blade Runner","year":1982,"director":"Ridley Scott"} + +# List all movies +curl https:///movies + +# Get a movie by ID +curl https:///movies/ + +# Update a movie +curl -X PUT https:///movies/ \ + -H "Content-Type: application/json" \ + -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott","rating":8.1}' + +# Delete a movie +curl -X DELETE https:///movies/ +``` + +The OpenAPI specification is available at `https:///v3/api-docs` and the interactive Swagger UI at `https:///swagger-ui.html`. + +## BTP Service Bindings + +The `--mount-service-binding-secret` flag mounts a BTP service instance secret into your workload following the [Service Binding Specification](https://servicebinding.io/): + +1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit +2. Create a service binding — this produces a Kubernetes Secret with credentials +3. Pass the secret name to `--mount-service-binding-secret` + +The secret is mounted at `/bindings/secret-` (read-only), and `SERVICE_BINDING_ROOT=/bindings` is set automatically. Your application reads credentials from the mounted path. + +## Evolution: Move to GitHub Actions CD + +Once your prototype stabilizes, automate deployments on every push using the [`kyma-project/setup-kyma-cli/app-push`](https://github.com/kyma-project/setup-kyma-cli/tree/main/app-push) GitHub Action. + +The action wraps the same `kyma app push` command you ran locally — same flags, same behavior: + +```yaml +# .github/workflows/deploy.yml +name: Deploy to Kyma +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: kyma-project/setup-kyma-cli/app-push@v1 + with: + name: my-prototype + code-path: "." + container-port: "8080" + expose: "true" + istio-inject: "true" + mount-service-binding-secret: object-store-binding + kubeconfig: ${{ secrets.KYMA_KUBECONFIG }} +``` + +Store your Kyma kubeconfig (base64-encoded) as a GitHub repository secret named `KYMA_KUBECONFIG`. Every push to `main` now triggers a fresh build and deploy — no local tooling required. + +## Summary + +With `kyma app push` you go from source code to a running, externally accessible application with BTP service bindings in a single command. The same deployment can then be moved into a GitHub Actions workflow with zero code changes — just copy the flags into the action inputs. + +This is not a throwaway prototype tool. The Deployment, Service, and APIRule it creates are standard Kubernetes resources you can later manage with Helm, Kustomize, or any GitOps tool. diff --git a/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md b/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md new file mode 100644 index 000000000..313386a01 --- /dev/null +++ b/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md @@ -0,0 +1,103 @@ +# Fast Prototyping on SAP BTP Kyma: Serverless Functions + +This tutorial shows how to deploy a serverless function to SAP BTP Kyma runtime with BTP service bindings using the CLI, then evolve it into a fully self-managed application by ejecting to plain Kubernetes manifests. No Dockerfile, no image registry, no Deployment manifests — just write a function and deploy. + +It is a good fit when you're building a lightweight API, webhook handler, or event processor and want the fastest path from code to a running workload with BTP service bindings (e.g., Object Store, XSUAA, HANA Cloud) — while keeping an escape hatch to "eject" into standard Kubernetes resources later. + +> For multi-language apps or when you want buildpack-based deployments with a GitHub Actions CD path, see [Fast Prototyping With App Push](01-40-fast-prototyping-app-push.md). + +## Prerequisites + +Install the Kyma CLI and enable the serverless module: + +```bash +# Install Kyma CLI (macOS/Linux) +curl -fsSL https://get.kyma.io | bash + +# Enable the serverless module +kyma module add serverless --default-config-cr +``` + +## Step 1: Scaffold a Function + +```bash +mkdir my-function && cd my-function + +kyma function init --runtime nodejs22 +``` + +This creates a local `handler.js` and `package.json`. Edit the handler to use the BTP Object Store binding: + +```javascript +// handler.js +const fs = require('fs'); + +module.exports = { + main: async function (event, context) { + // Access BTP Object Store via mounted service binding + const bindingPath = '/bindings/object-store'; + try { + const creds = JSON.parse(fs.readFileSync(`${bindingPath}/credentials`, 'utf8')); + return { statusCode: 200, body: JSON.stringify({ endpoint: creds.endpoint }) }; + } catch (err) { + return { statusCode: 500, body: JSON.stringify({ error: err.message }) }; + } + } +}; +``` + +## Step 2: Deploy + +Deploy the function with the BTP Object Store binding mounted: + +```bash +kyma function create my-function \ + --secret-mount object-store-binding=/bindings/object-store +``` + +The serverless module builds and runs the function. No container image, no registry, no Deployment manifest. + +## Step 3: Verify + +Check the function status and invoke it: + +```bash +kyma function get my-function + +# Port-forward to test locally +kubectl port-forward svc/my-function 8080:80 +curl http://localhost:8080 +# {"endpoint":"https://..."} +``` + +## BTP Service Bindings + +The `--secret-mount` flag mounts a BTP service instance secret into your function following the [Service Binding Specification](https://servicebinding.io/): + +1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit +2. Create a service binding — this produces a Kubernetes Secret with credentials +3. Pass the secret name and mount path to `--secret-mount` in the format `SECRET_NAME=MOUNT_PATH` + +Your function reads credentials from the mounted path at runtime. + +## Evolution: Eject to Kubernetes Manifests + +When your function outgrows the serverless model — you need custom resource limits, sidecar containers, or want to manage deployment with Helm/Kustomize — eject it: + +```bash +kyma function eject my-function --output-dir ./k8s-manifests +``` + +This generates plain Kubernetes YAML (Deployment, Service, ConfigMap with your source) in `./k8s-manifests/`. From here you fully own the deployment lifecycle: + +- Add it to a Helm chart +- Deploy with `kubectl apply` +- Wire it into any CI/CD pipeline (GitHub Actions, Tekton, ArgoCD) + +The function runtime is preserved — your code stays exactly the same. You just moved from "managed by Serverless module" to "managed by you." + +## Summary + +With `kyma function create` you go from a handler function to a running workload with BTP service bindings — zero container knowledge required. When your needs evolve, `kyma function eject` gives you full ownership of standard Kubernetes manifests without rewriting your application code. + +This is a stepping stone, not a dead end. Start fast, evolve at your own pace. diff --git a/examples/movies-api/pom.xml b/examples/movies-api/pom.xml new file mode 100644 index 000000000..0cb425590 --- /dev/null +++ b/examples/movies-api/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.3.0 + + + com.example + movies + 1.0.0 + + + 21 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + com.sap.cloud.environment.servicebinding + java-sap-service-operator + 0.10.6 + + + software.amazon.awssdk + s3 + 2.25.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/examples/movies-api/src/main/java/com/example/movies/Application.java b/examples/movies-api/src/main/java/com/example/movies/Application.java new file mode 100644 index 000000000..56165447d --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/Application.java @@ -0,0 +1,17 @@ +package com.example.movies; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info( + title = "Movies API", + version = "1.0.0", + description = "CRUD REST service for movies, backed by SAP BTP Object Store")) +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/Movie.java b/examples/movies-api/src/main/java/com/example/movies/Movie.java new file mode 100644 index 000000000..f9f62402f --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/Movie.java @@ -0,0 +1,20 @@ +package com.example.movies; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Movie resource") +public record Movie( + @Schema(description = "Auto-generated ID", example = "1714900000000", accessMode = Schema.AccessMode.READ_ONLY) + String id, + @Schema(description = "Movie title", example = "Blade Runner") + String title, + @Schema(description = "Release year", example = "1982") + int year, + @Schema(description = "Director name", example = "Ridley Scott") + String director, + @Schema(description = "Rating out of 10", example = "8.1") + Double rating) { + public Movie withId(String newId) { + return new Movie(newId, title, year, director, rating); + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/MovieController.java b/examples/movies-api/src/main/java/com/example/movies/MovieController.java new file mode 100644 index 000000000..937e1c0c4 --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/MovieController.java @@ -0,0 +1,85 @@ +package com.example.movies; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/movies") +@Tag(name = "Movies", description = "CRUD operations for movie resources") +public class MovieController { + + private final S3Client s3; + private final String bucket; + private final ObjectMapper mapper = new ObjectMapper(); + + public MovieController(S3Client s3, String bucketName) { + this.s3 = s3; + this.bucket = bucketName; + } + + @GetMapping + @Operation(summary = "List all movies") + public List list() throws IOException { + ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + return response.contents().stream() + .map(obj -> getMovie(obj.key())) + .toList(); + } + + @GetMapping("/{id}") + @Operation(summary = "Get a movie by ID") + public Movie get(@PathVariable String id) { + return getMovie("movies/" + id + ".json"); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "Create a new movie") + public Movie create(@RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); + putMovie(saved); + return saved; + } + + @PutMapping("/{id}") + @Operation(summary = "Update an existing movie") + public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(id); + putMovie(saved); + return saved; + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete a movie") + public void delete(@PathVariable String id) { + s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + } + + private void putMovie(Movie movie) throws Exception { + byte[] json = mapper.writeValueAsBytes(movie); + s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") + .contentType("application/json"), RequestBody.fromBytes(json)); + } + + private Movie getMovie(String key) { + try { + byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + return mapper.readValue(data, Movie.class); + } catch (NoSuchKeyException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java new file mode 100644 index 000000000..0e91424b6 --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java @@ -0,0 +1,44 @@ +package com.example.movies; + +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import java.net.URI; +import java.util.Map; + +@Configuration +public class ObjectStoreConfig { + + @Bean + public S3Client s3Client() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + + Map creds = binding.getCredentials(); + return S3Client.builder() + .region(Region.of((String) creds.get("region"))) + .endpointOverride(URI.create((String) creds.get("endpoint"))) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create( + (String) creds.get("access_key_id"), + (String) creds.get("secret_access_key")))) + .build(); + } + + @Bean + public String bucketName() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(); + return (String) binding.getCredentials().get("bucket"); + } +} diff --git a/examples/movies-api/src/main/resources/application.properties b/examples/movies-api/src/main/resources/application.properties new file mode 100644 index 000000000..4c00e40de --- /dev/null +++ b/examples/movies-api/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 From b4dccf17fe353c253bd147aaa330aa178289948d Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Tue, 5 May 2026 11:09:42 +0200 Subject: [PATCH 2/9] Add sample application --- .../01-40-fast-prototyping-app-push.md | 23 +++++++++- examples/movies-api/.env | 2 + examples/movies-api/README.md | 44 +++++++++++++++++++ examples/movies-api/k8s/service-binding.yaml | 6 +++ examples/movies-api/k8s/service-instance.yaml | 7 +++ examples/movies-api/pom.xml | 13 +++++- .../com/example/movies/MovieController.java | 31 +++++++++---- .../com/example/movies/ObjectStoreConfig.java | 35 ++++++++++++--- 8 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 examples/movies-api/.env create mode 100644 examples/movies-api/README.md create mode 100644 examples/movies-api/k8s/service-binding.yaml create mode 100644 examples/movies-api/k8s/service-instance.yaml diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index 6aa8bc493..7bf57f860 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -53,6 +53,18 @@ mkdir -p src/main/java/com/example/movies 21 + + + + com.sap.cloud.environment.servicebinding + java-bom + 0.10.5 + pom + import + + + + org.springframework.boot @@ -66,7 +78,6 @@ mkdir -p src/main/java/com/example/movies com.sap.cloud.environment.servicebinding java-sap-service-operator - 0.10.6 software.amazon.awssdk @@ -331,7 +342,15 @@ kyma app push \ --container-port 8080 \ --expose \ --istio-inject=true \ - --mount-service-binding-secret object-store-binding + --mount-service-binding-secret object-store-binding \ + --env-from-file .env +``` + +The `.env` file contains JVM memory tuning required to fit within the default 512Mi container limit: + +```properties +BPL_JVM_THREAD_COUNT=20 +JAVA_TOOL_OPTIONS=-XX:ReservedCodeCacheSize=40M -XX:MaxMetaspaceSize=80M -Xss512k ``` What happens under the hood: diff --git a/examples/movies-api/.env b/examples/movies-api/.env new file mode 100644 index 000000000..ebebf6cf0 --- /dev/null +++ b/examples/movies-api/.env @@ -0,0 +1,2 @@ +BPL_JVM_THREAD_COUNT=20 +JAVA_TOOL_OPTIONS=-XX:ReservedCodeCacheSize=40M -XX:MaxMetaspaceSize=80M -Xss512k diff --git a/examples/movies-api/README.md b/examples/movies-api/README.md new file mode 100644 index 000000000..c178e599a --- /dev/null +++ b/examples/movies-api/README.md @@ -0,0 +1,44 @@ +# Movies API + +A simple CRUD REST service for managing movies, backed by SAP BTP Object Store. Built with Spring Boot and designed to be deployed to SAP BTP Kyma runtime using `kyma app push`. + +## Prerequisites + +The service uses SAP BTP Object Store (S3-compatible) for persistence. A Kubernetes Secret named `object-store-binding` containing the Object Store service binding credentials must exist in the same namespace before deployment. See `k8s/service-instance.yaml` and `k8s/service-binding.yaml` for the required resources. + +## Deploy + +```bash +kyma app push \ + --name my-prototype \ + --code-path . \ + --container-port 8080 \ + --expose \ + --istio-inject=true \ + --mount-service-binding-secret object-store-binding \ + --env-from-file .env +``` + +## API Documentation + +Once deployed, the Swagger UI is available at: + +``` +https:///swagger-ui.html +``` + +The OpenAPI spec (JSON) is at: + +``` +https:///v3/api-docs +``` + +## Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| GET | /movies | List all movies | +| GET | /movies/{id} | Get a movie by ID | +| POST | /movies | Create a new movie | +| PUT | /movies/{id} | Update a movie | +| DELETE | /movies/{id} | Delete a movie | diff --git a/examples/movies-api/k8s/service-binding.yaml b/examples/movies-api/k8s/service-binding.yaml new file mode 100644 index 000000000..5146ef9b3 --- /dev/null +++ b/examples/movies-api/k8s/service-binding.yaml @@ -0,0 +1,6 @@ +apiVersion: services.cloud.sap.com/v1 +kind: ServiceBinding +metadata: + name: object-store-binding +spec: + serviceInstanceName: object-store-instance \ No newline at end of file diff --git a/examples/movies-api/k8s/service-instance.yaml b/examples/movies-api/k8s/service-instance.yaml new file mode 100644 index 000000000..43fb7586a --- /dev/null +++ b/examples/movies-api/k8s/service-instance.yaml @@ -0,0 +1,7 @@ +apiVersion: services.cloud.sap.com/v1 +kind: ServiceInstance +metadata: + name: object-store-instance +spec: + serviceOfferingName: objectstore + servicePlanName: standard \ No newline at end of file diff --git a/examples/movies-api/pom.xml b/examples/movies-api/pom.xml index 0cb425590..f3fef918e 100644 --- a/examples/movies-api/pom.xml +++ b/examples/movies-api/pom.xml @@ -18,6 +18,18 @@ 21 + + + + com.sap.cloud.environment.servicebinding + java-bom + 0.10.5 + pom + import + + + + org.springframework.boot @@ -31,7 +43,6 @@ com.sap.cloud.environment.servicebinding java-sap-service-operator - 0.10.6 software.amazon.awssdk diff --git a/examples/movies-api/src/main/java/com/example/movies/MovieController.java b/examples/movies-api/src/main/java/com/example/movies/MovieController.java index 937e1c0c4..4877227d6 100644 --- a/examples/movies-api/src/main/java/com/example/movies/MovieController.java +++ b/examples/movies-api/src/main/java/com/example/movies/MovieController.java @@ -6,7 +6,6 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; -import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.*; @@ -30,7 +29,11 @@ public MovieController(S3Client s3, String bucketName) { @GetMapping @Operation(summary = "List all movies") public List list() throws IOException { - ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + ListObjectsV2Request request = ListObjectsV2Request.builder() + .bucket(bucket) + .prefix("movies/") + .build(); + ListObjectsV2Response response = s3.listObjectsV2(request); return response.contents().stream() .map(obj -> getMovie(obj.key())) .toList(); @@ -45,7 +48,7 @@ public Movie get(@PathVariable String id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) @Operation(summary = "Create a new movie") - public Movie create(@RequestBody Movie movie) throws Exception { + public Movie create(@org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); putMovie(saved); return saved; @@ -53,7 +56,7 @@ public Movie create(@RequestBody Movie movie) throws Exception { @PutMapping("/{id}") @Operation(summary = "Update an existing movie") - public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + public Movie update(@PathVariable String id, @org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(id); putMovie(saved); return saved; @@ -63,18 +66,30 @@ public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Ex @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Delete a movie") public void delete(@PathVariable String id) { - s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + DeleteObjectRequest request = DeleteObjectRequest.builder() + .bucket(bucket) + .key("movies/" + id + ".json") + .build(); + s3.deleteObject(request); } private void putMovie(Movie movie) throws Exception { byte[] json = mapper.writeValueAsBytes(movie); - s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") - .contentType("application/json"), RequestBody.fromBytes(json)); + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucket) + .key("movies/" + movie.id() + ".json") + .contentType("application/json") + .build(); + s3.putObject(request, software.amazon.awssdk.core.sync.RequestBody.fromBytes(json)); } private Movie getMovie(String key) { try { - byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + GetObjectRequest request = GetObjectRequest.builder() + .bucket(bucket) + .key(key) + .build(); + byte[] data = s3.getObject(request).readAllBytes(); return mapper.readValue(data, Movie.class); } catch (NoSuchKeyException e) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); diff --git a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java index 0e91424b6..51a9bb2af 100644 --- a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java +++ b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java @@ -2,6 +2,9 @@ import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; @@ -10,22 +13,41 @@ import software.amazon.awssdk.services.s3.S3Client; import java.net.URI; +import java.util.List; import java.util.Map; @Configuration public class ObjectStoreConfig { + private static final Logger log = LoggerFactory.getLogger(ObjectStoreConfig.class); + @Bean public S3Client s3Client() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + List allBindings = accessor.getServiceBindings(); + + log.info("SERVICE_BINDING_ROOT = {}", System.getenv("SERVICE_BINDING_ROOT")); + log.info("Found {} service binding(s):", allBindings.size()); + for (ServiceBinding b : allBindings) { + log.info(" - name={}, serviceName={}, servicePlan={}, tags={}, keys={}", + b.getName().orElse("(none)"), + b.getServiceName().orElse("(none)"), + b.getServicePlan().orElse("(none)"), + b.getTags(), + b.getKeys()); + } + + ServiceBinding binding = allBindings.stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() - .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + .orElseThrow(() -> new IllegalStateException("No matching Object Store binding found")); Map creds = binding.getCredentials(); + log.info("Credentials keys: {}", creds.keySet()); + return S3Client.builder() .region(Region.of((String) creds.get("region"))) - .endpointOverride(URI.create((String) creds.get("endpoint"))) + .endpointOverride(URI.create("https://" + creds.get("host"))) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create( (String) creds.get("access_key_id"), @@ -35,8 +57,9 @@ public S3Client s3Client() { @Bean public String bucketName() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + ServiceBinding binding = accessor.getServiceBindings().stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() .orElseThrow(); return (String) binding.getCredentials().get("bucket"); From 14a435877285a2c482be7ae1cf62a00c774a5e97 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Mon, 4 May 2026 12:05:58 +0200 Subject: [PATCH 3/9] Single container app tutorials --- .../01-40-fast-prototyping-app-push.md | 424 ++++++++++++++++++ ...0-fast-prototyping-serverless-functions.md | 103 +++++ examples/movies-api/pom.xml | 51 +++ .../java/com/example/movies/Application.java | 17 + .../main/java/com/example/movies/Movie.java | 20 + .../com/example/movies/MovieController.java | 85 ++++ .../com/example/movies/ObjectStoreConfig.java | 44 ++ .../src/main/resources/application.properties | 1 + 8 files changed, 745 insertions(+) create mode 100644 docs/user/tutorials/01-40-fast-prototyping-app-push.md create mode 100644 docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md create mode 100644 examples/movies-api/pom.xml create mode 100644 examples/movies-api/src/main/java/com/example/movies/Application.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/Movie.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/MovieController.java create mode 100644 examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java create mode 100644 examples/movies-api/src/main/resources/application.properties diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md new file mode 100644 index 000000000..6aa8bc493 --- /dev/null +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -0,0 +1,424 @@ +# Fast Prototyping on SAP BTP Kyma: App Push + +This tutorial shows how to deploy a single-container application to SAP BTP Kyma runtime in one CLI command using `kyma app push`, then evolve it into an automated GitHub Actions CD pipeline. No YAML hand-crafting, no container registry setup, no CI/CD pipeline to configure upfront — just code → deploy → iterate. + +It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET), need BTP service bindings (e.g., Object Store), and want a clear path from local development to automated CD — all without writing a Dockerfile. + +> For lightweight event-driven workloads where you want zero container knowledge, see [Fast Prototyping With Serverless Functions](01-50-fast-prototyping-serverless-functions.md). + +## Prerequisites + +- [Kyma CLI](https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-cli?locale=en-US#install-kyma-cli) installed. +- The following [Kyma modules enabled](https://help.sap.com/docs/btp/sap-business-technology-platform/enable-and-disable-kyma-module#adding-a-kyma-module) on your runtime: + - **Istio** (enabled by default) — service mesh and networking + - **API Gateway** (enabled by default) — external exposure via APIRule + - **BTP Operator** (enabled by default) — manages BTP service instances and bindings + - **Docker Registry** ([community module](https://kyma-project.io/external-content/community-modules/docs/user/README.html#quick-install)) — in-cluster container registry for building and storing images (no external registry needed) +- Your SAP BTP subaccount must be **entitled to use the SAP Object Store service** (service plan `standard`). Add the entitlement in the BTP cockpit under *Entitlements* if not already assigned. + +## Step 1: Create Your App + +For this example, use a Spring Boot application that exposes a REST API for managing movies, storing data in BTP Object Store: + +```bash +mkdir my-prototype && cd my-prototype +``` + +Create the Maven project structure: + +```bash +mkdir -p src/main/java/com/example/movies +``` + +**pom.xml**: + +```xml + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.3.0 + + + com.example + movies + 1.0.0 + + + 21 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + com.sap.cloud.environment.servicebinding + java-sap-service-operator + 0.10.6 + + + software.amazon.awssdk + s3 + 2.25.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +``` + +**src/main/java/com/example/movies/Application.java**: + +```java +package com.example.movies; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info( + title = "Movies API", + version = "1.0.0", + description = "CRUD REST service for movies, backed by SAP BTP Object Store")) +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + +**src/main/java/com/example/movies/ObjectStoreConfig.java**: + +```java +package com.example.movies; + +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import java.net.URI; +import java.util.Map; + +@Configuration +public class ObjectStoreConfig { + + @Bean + public S3Client s3Client() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + + Map creds = binding.getCredentials(); + return S3Client.builder() + .region(Region.of((String) creds.get("region"))) + .endpointOverride(URI.create((String) creds.get("endpoint"))) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create( + (String) creds.get("access_key_id"), + (String) creds.get("secret_access_key")))) + .build(); + } + + @Bean + public String bucketName() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(); + return (String) binding.getCredentials().get("bucket"); + } +} +``` + +**src/main/java/com/example/movies/Movie.java**: + +```java +package com.example.movies; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Movie resource") +public record Movie( + @Schema(description = "Auto-generated ID", example = "1714900000000", accessMode = Schema.AccessMode.READ_ONLY) + String id, + @Schema(description = "Movie title", example = "Blade Runner") + String title, + @Schema(description = "Release year", example = "1982") + int year, + @Schema(description = "Director name", example = "Ridley Scott") + String director, + @Schema(description = "Rating out of 10", example = "8.1") + Double rating) { + public Movie withId(String newId) { + return new Movie(newId, title, year, director, rating); + } +} +``` + +**src/main/java/com/example/movies/MovieController.java**: + +```java +package com.example.movies; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/movies") +@Tag(name = "Movies", description = "CRUD operations for movie resources") +public class MovieController { + + private final S3Client s3; + private final String bucket; + private final ObjectMapper mapper = new ObjectMapper(); + + public MovieController(S3Client s3, String bucketName) { + this.s3 = s3; + this.bucket = bucketName; + } + + @GetMapping + @Operation(summary = "List all movies") + public List list() throws IOException { + ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + return response.contents().stream() + .map(obj -> getMovie(obj.key())) + .toList(); + } + + @GetMapping("/{id}") + @Operation(summary = "Get a movie by ID") + public Movie get(@PathVariable String id) { + return getMovie("movies/" + id + ".json"); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "Create a new movie") + public Movie create(@RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); + putMovie(saved); + return saved; + } + + @PutMapping("/{id}") + @Operation(summary = "Update an existing movie") + public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(id); + putMovie(saved); + return saved; + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete a movie") + public void delete(@PathVariable String id) { + s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + } + + private void putMovie(Movie movie) throws Exception { + byte[] json = mapper.writeValueAsBytes(movie); + s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") + .contentType("application/json"), RequestBody.fromBytes(json)); + } + + private Movie getMovie(String key) { + try { + byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + return mapper.readValue(data, Movie.class); + } catch (NoSuchKeyException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} +``` + +**src/main/resources/application.properties**: + +```properties +server.port=8080 +``` + +## Step 2: Create the BTP Object Store Service Instance and Binding + +Create the service instance and binding using the BTP Operator API (provided by the btp-manager module): + +```yaml +# service-instance.yaml +apiVersion: services.cloud.sap.com/v1 +kind: ServiceInstance +metadata: + name: object-store-instance + namespace: default +spec: + serviceOfferingName: objectstore + servicePlanName: standard +``` + +```yaml +# service-binding.yaml +apiVersion: services.cloud.sap.com/v1 +kind: ServiceBinding +metadata: + name: object-store-binding + namespace: default +spec: + serviceInstanceName: object-store-instance +``` + +Apply both resources: + +```bash +kubectl apply -f service-instance.yaml +kubectl apply -f service-binding.yaml +``` + +Wait for the binding to become ready: + +```bash +kubectl get servicebindings object-store-binding -w +``` + +Once the status shows `Ready: True`, a Kubernetes Secret named `object-store-binding` is created in the namespace with the Object Store credentials. + +## Step 3: Deploy + +One command builds, pushes, and deploys your app — and exposes it externally: + +```bash +kyma app push \ + --name my-prototype \ + --code-path . \ + --container-port 8080 \ + --expose \ + --istio-inject=true \ + --mount-service-binding-secret object-store-binding +``` + +What happens under the hood: +1. Source code is built into a container image using [Cloud Native Buildpacks](https://buildpacks.io/) (Paketo) +2. Image is pushed to the in-cluster docker-registry +3. A Deployment, Service, and APIRule are created +4. The BTP Object Store binding secret is mounted at `/bindings/secret-object-store-binding` +5. `SERVICE_BINDING_ROOT=/bindings` environment variable is set automatically + +> No Dockerfile required. Buildpacks detect `pom.xml` and automatically build a Java application with the correct JDK. The same approach works for Node.js, Go, Python, .NET, and more. + +## Step 4: Verify + +The command outputs the external URL of your app. Test the CRUD operations: + +```bash +# Health check +curl https:///health +# {"status":"UP"} + +# Create a movie +curl -X POST https:///movies \ + -H "Content-Type: application/json" \ + -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott"}' +# {"id":"1714900000000","title":"Blade Runner","year":1982,"director":"Ridley Scott"} + +# List all movies +curl https:///movies + +# Get a movie by ID +curl https:///movies/ + +# Update a movie +curl -X PUT https:///movies/ \ + -H "Content-Type: application/json" \ + -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott","rating":8.1}' + +# Delete a movie +curl -X DELETE https:///movies/ +``` + +The OpenAPI specification is available at `https:///v3/api-docs` and the interactive Swagger UI at `https:///swagger-ui.html`. + +## BTP Service Bindings + +The `--mount-service-binding-secret` flag mounts a BTP service instance secret into your workload following the [Service Binding Specification](https://servicebinding.io/): + +1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit +2. Create a service binding — this produces a Kubernetes Secret with credentials +3. Pass the secret name to `--mount-service-binding-secret` + +The secret is mounted at `/bindings/secret-` (read-only), and `SERVICE_BINDING_ROOT=/bindings` is set automatically. Your application reads credentials from the mounted path. + +## Evolution: Move to GitHub Actions CD + +Once your prototype stabilizes, automate deployments on every push using the [`kyma-project/setup-kyma-cli/app-push`](https://github.com/kyma-project/setup-kyma-cli/tree/main/app-push) GitHub Action. + +The action wraps the same `kyma app push` command you ran locally — same flags, same behavior: + +```yaml +# .github/workflows/deploy.yml +name: Deploy to Kyma +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: kyma-project/setup-kyma-cli/app-push@v1 + with: + name: my-prototype + code-path: "." + container-port: "8080" + expose: "true" + istio-inject: "true" + mount-service-binding-secret: object-store-binding + kubeconfig: ${{ secrets.KYMA_KUBECONFIG }} +``` + +Store your Kyma kubeconfig (base64-encoded) as a GitHub repository secret named `KYMA_KUBECONFIG`. Every push to `main` now triggers a fresh build and deploy — no local tooling required. + +## Summary + +With `kyma app push` you go from source code to a running, externally accessible application with BTP service bindings in a single command. The same deployment can then be moved into a GitHub Actions workflow with zero code changes — just copy the flags into the action inputs. + +This is not a throwaway prototype tool. The Deployment, Service, and APIRule it creates are standard Kubernetes resources you can later manage with Helm, Kustomize, or any GitOps tool. diff --git a/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md b/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md new file mode 100644 index 000000000..313386a01 --- /dev/null +++ b/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md @@ -0,0 +1,103 @@ +# Fast Prototyping on SAP BTP Kyma: Serverless Functions + +This tutorial shows how to deploy a serverless function to SAP BTP Kyma runtime with BTP service bindings using the CLI, then evolve it into a fully self-managed application by ejecting to plain Kubernetes manifests. No Dockerfile, no image registry, no Deployment manifests — just write a function and deploy. + +It is a good fit when you're building a lightweight API, webhook handler, or event processor and want the fastest path from code to a running workload with BTP service bindings (e.g., Object Store, XSUAA, HANA Cloud) — while keeping an escape hatch to "eject" into standard Kubernetes resources later. + +> For multi-language apps or when you want buildpack-based deployments with a GitHub Actions CD path, see [Fast Prototyping With App Push](01-40-fast-prototyping-app-push.md). + +## Prerequisites + +Install the Kyma CLI and enable the serverless module: + +```bash +# Install Kyma CLI (macOS/Linux) +curl -fsSL https://get.kyma.io | bash + +# Enable the serverless module +kyma module add serverless --default-config-cr +``` + +## Step 1: Scaffold a Function + +```bash +mkdir my-function && cd my-function + +kyma function init --runtime nodejs22 +``` + +This creates a local `handler.js` and `package.json`. Edit the handler to use the BTP Object Store binding: + +```javascript +// handler.js +const fs = require('fs'); + +module.exports = { + main: async function (event, context) { + // Access BTP Object Store via mounted service binding + const bindingPath = '/bindings/object-store'; + try { + const creds = JSON.parse(fs.readFileSync(`${bindingPath}/credentials`, 'utf8')); + return { statusCode: 200, body: JSON.stringify({ endpoint: creds.endpoint }) }; + } catch (err) { + return { statusCode: 500, body: JSON.stringify({ error: err.message }) }; + } + } +}; +``` + +## Step 2: Deploy + +Deploy the function with the BTP Object Store binding mounted: + +```bash +kyma function create my-function \ + --secret-mount object-store-binding=/bindings/object-store +``` + +The serverless module builds and runs the function. No container image, no registry, no Deployment manifest. + +## Step 3: Verify + +Check the function status and invoke it: + +```bash +kyma function get my-function + +# Port-forward to test locally +kubectl port-forward svc/my-function 8080:80 +curl http://localhost:8080 +# {"endpoint":"https://..."} +``` + +## BTP Service Bindings + +The `--secret-mount` flag mounts a BTP service instance secret into your function following the [Service Binding Specification](https://servicebinding.io/): + +1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit +2. Create a service binding — this produces a Kubernetes Secret with credentials +3. Pass the secret name and mount path to `--secret-mount` in the format `SECRET_NAME=MOUNT_PATH` + +Your function reads credentials from the mounted path at runtime. + +## Evolution: Eject to Kubernetes Manifests + +When your function outgrows the serverless model — you need custom resource limits, sidecar containers, or want to manage deployment with Helm/Kustomize — eject it: + +```bash +kyma function eject my-function --output-dir ./k8s-manifests +``` + +This generates plain Kubernetes YAML (Deployment, Service, ConfigMap with your source) in `./k8s-manifests/`. From here you fully own the deployment lifecycle: + +- Add it to a Helm chart +- Deploy with `kubectl apply` +- Wire it into any CI/CD pipeline (GitHub Actions, Tekton, ArgoCD) + +The function runtime is preserved — your code stays exactly the same. You just moved from "managed by Serverless module" to "managed by you." + +## Summary + +With `kyma function create` you go from a handler function to a running workload with BTP service bindings — zero container knowledge required. When your needs evolve, `kyma function eject` gives you full ownership of standard Kubernetes manifests without rewriting your application code. + +This is a stepping stone, not a dead end. Start fast, evolve at your own pace. diff --git a/examples/movies-api/pom.xml b/examples/movies-api/pom.xml new file mode 100644 index 000000000..0cb425590 --- /dev/null +++ b/examples/movies-api/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.3.0 + + + com.example + movies + 1.0.0 + + + 21 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + + + com.sap.cloud.environment.servicebinding + java-sap-service-operator + 0.10.6 + + + software.amazon.awssdk + s3 + 2.25.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/examples/movies-api/src/main/java/com/example/movies/Application.java b/examples/movies-api/src/main/java/com/example/movies/Application.java new file mode 100644 index 000000000..56165447d --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/Application.java @@ -0,0 +1,17 @@ +package com.example.movies; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@OpenAPIDefinition(info = @Info( + title = "Movies API", + version = "1.0.0", + description = "CRUD REST service for movies, backed by SAP BTP Object Store")) +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/Movie.java b/examples/movies-api/src/main/java/com/example/movies/Movie.java new file mode 100644 index 000000000..f9f62402f --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/Movie.java @@ -0,0 +1,20 @@ +package com.example.movies; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "Movie resource") +public record Movie( + @Schema(description = "Auto-generated ID", example = "1714900000000", accessMode = Schema.AccessMode.READ_ONLY) + String id, + @Schema(description = "Movie title", example = "Blade Runner") + String title, + @Schema(description = "Release year", example = "1982") + int year, + @Schema(description = "Director name", example = "Ridley Scott") + String director, + @Schema(description = "Rating out of 10", example = "8.1") + Double rating) { + public Movie withId(String newId) { + return new Movie(newId, title, year, director, rating); + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/MovieController.java b/examples/movies-api/src/main/java/com/example/movies/MovieController.java new file mode 100644 index 000000000..937e1c0c4 --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/MovieController.java @@ -0,0 +1,85 @@ +package com.example.movies; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.*; + +import java.io.IOException; +import java.util.List; + +@RestController +@RequestMapping("/movies") +@Tag(name = "Movies", description = "CRUD operations for movie resources") +public class MovieController { + + private final S3Client s3; + private final String bucket; + private final ObjectMapper mapper = new ObjectMapper(); + + public MovieController(S3Client s3, String bucketName) { + this.s3 = s3; + this.bucket = bucketName; + } + + @GetMapping + @Operation(summary = "List all movies") + public List list() throws IOException { + ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + return response.contents().stream() + .map(obj -> getMovie(obj.key())) + .toList(); + } + + @GetMapping("/{id}") + @Operation(summary = "Get a movie by ID") + public Movie get(@PathVariable String id) { + return getMovie("movies/" + id + ".json"); + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "Create a new movie") + public Movie create(@RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); + putMovie(saved); + return saved; + } + + @PutMapping("/{id}") + @Operation(summary = "Update an existing movie") + public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + Movie saved = movie.withId(id); + putMovie(saved); + return saved; + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete a movie") + public void delete(@PathVariable String id) { + s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + } + + private void putMovie(Movie movie) throws Exception { + byte[] json = mapper.writeValueAsBytes(movie); + s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") + .contentType("application/json"), RequestBody.fromBytes(json)); + } + + private Movie getMovie(String key) { + try { + byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + return mapper.readValue(data, Movie.class); + } catch (NoSuchKeyException e) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java new file mode 100644 index 000000000..0e91424b6 --- /dev/null +++ b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java @@ -0,0 +1,44 @@ +package com.example.movies; + +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; +import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; + +import java.net.URI; +import java.util.Map; + +@Configuration +public class ObjectStoreConfig { + + @Bean + public S3Client s3Client() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + + Map creds = binding.getCredentials(); + return S3Client.builder() + .region(Region.of((String) creds.get("region"))) + .endpointOverride(URI.create((String) creds.get("endpoint"))) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create( + (String) creds.get("access_key_id"), + (String) creds.get("secret_access_key")))) + .build(); + } + + @Bean + public String bucketName() { + ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() + .filter(b -> b.getTags().contains("objectstore")) + .findFirst() + .orElseThrow(); + return (String) binding.getCredentials().get("bucket"); + } +} diff --git a/examples/movies-api/src/main/resources/application.properties b/examples/movies-api/src/main/resources/application.properties new file mode 100644 index 000000000..4c00e40de --- /dev/null +++ b/examples/movies-api/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 From 3e12ce80ef072ea59ea8b42cfdbbe1ea4c70b836 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Tue, 5 May 2026 11:09:42 +0200 Subject: [PATCH 4/9] Add sample application --- .../01-40-fast-prototyping-app-push.md | 23 +++++++++- examples/movies-api/.env | 2 + examples/movies-api/README.md | 44 +++++++++++++++++++ examples/movies-api/k8s/service-binding.yaml | 6 +++ examples/movies-api/k8s/service-instance.yaml | 7 +++ examples/movies-api/pom.xml | 13 +++++- .../com/example/movies/MovieController.java | 31 +++++++++---- .../com/example/movies/ObjectStoreConfig.java | 35 ++++++++++++--- 8 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 examples/movies-api/.env create mode 100644 examples/movies-api/README.md create mode 100644 examples/movies-api/k8s/service-binding.yaml create mode 100644 examples/movies-api/k8s/service-instance.yaml diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index 6aa8bc493..7bf57f860 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -53,6 +53,18 @@ mkdir -p src/main/java/com/example/movies 21 + + + + com.sap.cloud.environment.servicebinding + java-bom + 0.10.5 + pom + import + + + + org.springframework.boot @@ -66,7 +78,6 @@ mkdir -p src/main/java/com/example/movies com.sap.cloud.environment.servicebinding java-sap-service-operator - 0.10.6 software.amazon.awssdk @@ -331,7 +342,15 @@ kyma app push \ --container-port 8080 \ --expose \ --istio-inject=true \ - --mount-service-binding-secret object-store-binding + --mount-service-binding-secret object-store-binding \ + --env-from-file .env +``` + +The `.env` file contains JVM memory tuning required to fit within the default 512Mi container limit: + +```properties +BPL_JVM_THREAD_COUNT=20 +JAVA_TOOL_OPTIONS=-XX:ReservedCodeCacheSize=40M -XX:MaxMetaspaceSize=80M -Xss512k ``` What happens under the hood: diff --git a/examples/movies-api/.env b/examples/movies-api/.env new file mode 100644 index 000000000..ebebf6cf0 --- /dev/null +++ b/examples/movies-api/.env @@ -0,0 +1,2 @@ +BPL_JVM_THREAD_COUNT=20 +JAVA_TOOL_OPTIONS=-XX:ReservedCodeCacheSize=40M -XX:MaxMetaspaceSize=80M -Xss512k diff --git a/examples/movies-api/README.md b/examples/movies-api/README.md new file mode 100644 index 000000000..c178e599a --- /dev/null +++ b/examples/movies-api/README.md @@ -0,0 +1,44 @@ +# Movies API + +A simple CRUD REST service for managing movies, backed by SAP BTP Object Store. Built with Spring Boot and designed to be deployed to SAP BTP Kyma runtime using `kyma app push`. + +## Prerequisites + +The service uses SAP BTP Object Store (S3-compatible) for persistence. A Kubernetes Secret named `object-store-binding` containing the Object Store service binding credentials must exist in the same namespace before deployment. See `k8s/service-instance.yaml` and `k8s/service-binding.yaml` for the required resources. + +## Deploy + +```bash +kyma app push \ + --name my-prototype \ + --code-path . \ + --container-port 8080 \ + --expose \ + --istio-inject=true \ + --mount-service-binding-secret object-store-binding \ + --env-from-file .env +``` + +## API Documentation + +Once deployed, the Swagger UI is available at: + +``` +https:///swagger-ui.html +``` + +The OpenAPI spec (JSON) is at: + +``` +https:///v3/api-docs +``` + +## Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| GET | /movies | List all movies | +| GET | /movies/{id} | Get a movie by ID | +| POST | /movies | Create a new movie | +| PUT | /movies/{id} | Update a movie | +| DELETE | /movies/{id} | Delete a movie | diff --git a/examples/movies-api/k8s/service-binding.yaml b/examples/movies-api/k8s/service-binding.yaml new file mode 100644 index 000000000..5146ef9b3 --- /dev/null +++ b/examples/movies-api/k8s/service-binding.yaml @@ -0,0 +1,6 @@ +apiVersion: services.cloud.sap.com/v1 +kind: ServiceBinding +metadata: + name: object-store-binding +spec: + serviceInstanceName: object-store-instance \ No newline at end of file diff --git a/examples/movies-api/k8s/service-instance.yaml b/examples/movies-api/k8s/service-instance.yaml new file mode 100644 index 000000000..43fb7586a --- /dev/null +++ b/examples/movies-api/k8s/service-instance.yaml @@ -0,0 +1,7 @@ +apiVersion: services.cloud.sap.com/v1 +kind: ServiceInstance +metadata: + name: object-store-instance +spec: + serviceOfferingName: objectstore + servicePlanName: standard \ No newline at end of file diff --git a/examples/movies-api/pom.xml b/examples/movies-api/pom.xml index 0cb425590..f3fef918e 100644 --- a/examples/movies-api/pom.xml +++ b/examples/movies-api/pom.xml @@ -18,6 +18,18 @@ 21 + + + + com.sap.cloud.environment.servicebinding + java-bom + 0.10.5 + pom + import + + + + org.springframework.boot @@ -31,7 +43,6 @@ com.sap.cloud.environment.servicebinding java-sap-service-operator - 0.10.6 software.amazon.awssdk diff --git a/examples/movies-api/src/main/java/com/example/movies/MovieController.java b/examples/movies-api/src/main/java/com/example/movies/MovieController.java index 937e1c0c4..4877227d6 100644 --- a/examples/movies-api/src/main/java/com/example/movies/MovieController.java +++ b/examples/movies-api/src/main/java/com/example/movies/MovieController.java @@ -6,7 +6,6 @@ import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; -import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.*; @@ -30,7 +29,11 @@ public MovieController(S3Client s3, String bucketName) { @GetMapping @Operation(summary = "List all movies") public List list() throws IOException { - ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + ListObjectsV2Request request = ListObjectsV2Request.builder() + .bucket(bucket) + .prefix("movies/") + .build(); + ListObjectsV2Response response = s3.listObjectsV2(request); return response.contents().stream() .map(obj -> getMovie(obj.key())) .toList(); @@ -45,7 +48,7 @@ public Movie get(@PathVariable String id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) @Operation(summary = "Create a new movie") - public Movie create(@RequestBody Movie movie) throws Exception { + public Movie create(@org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); putMovie(saved); return saved; @@ -53,7 +56,7 @@ public Movie create(@RequestBody Movie movie) throws Exception { @PutMapping("/{id}") @Operation(summary = "Update an existing movie") - public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + public Movie update(@PathVariable String id, @org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(id); putMovie(saved); return saved; @@ -63,18 +66,30 @@ public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Ex @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Delete a movie") public void delete(@PathVariable String id) { - s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + DeleteObjectRequest request = DeleteObjectRequest.builder() + .bucket(bucket) + .key("movies/" + id + ".json") + .build(); + s3.deleteObject(request); } private void putMovie(Movie movie) throws Exception { byte[] json = mapper.writeValueAsBytes(movie); - s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") - .contentType("application/json"), RequestBody.fromBytes(json)); + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucket) + .key("movies/" + movie.id() + ".json") + .contentType("application/json") + .build(); + s3.putObject(request, software.amazon.awssdk.core.sync.RequestBody.fromBytes(json)); } private Movie getMovie(String key) { try { - byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + GetObjectRequest request = GetObjectRequest.builder() + .bucket(bucket) + .key(key) + .build(); + byte[] data = s3.getObject(request).readAllBytes(); return mapper.readValue(data, Movie.class); } catch (NoSuchKeyException e) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); diff --git a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java index 0e91424b6..51a9bb2af 100644 --- a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java +++ b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java @@ -2,6 +2,9 @@ import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; @@ -10,22 +13,41 @@ import software.amazon.awssdk.services.s3.S3Client; import java.net.URI; +import java.util.List; import java.util.Map; @Configuration public class ObjectStoreConfig { + private static final Logger log = LoggerFactory.getLogger(ObjectStoreConfig.class); + @Bean public S3Client s3Client() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + List allBindings = accessor.getServiceBindings(); + + log.info("SERVICE_BINDING_ROOT = {}", System.getenv("SERVICE_BINDING_ROOT")); + log.info("Found {} service binding(s):", allBindings.size()); + for (ServiceBinding b : allBindings) { + log.info(" - name={}, serviceName={}, servicePlan={}, tags={}, keys={}", + b.getName().orElse("(none)"), + b.getServiceName().orElse("(none)"), + b.getServicePlan().orElse("(none)"), + b.getTags(), + b.getKeys()); + } + + ServiceBinding binding = allBindings.stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() - .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + .orElseThrow(() -> new IllegalStateException("No matching Object Store binding found")); Map creds = binding.getCredentials(); + log.info("Credentials keys: {}", creds.keySet()); + return S3Client.builder() .region(Region.of((String) creds.get("region"))) - .endpointOverride(URI.create((String) creds.get("endpoint"))) + .endpointOverride(URI.create("https://" + creds.get("host"))) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create( (String) creds.get("access_key_id"), @@ -35,8 +57,9 @@ public S3Client s3Client() { @Bean public String bucketName() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + ServiceBinding binding = accessor.getServiceBindings().stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() .orElseThrow(); return (String) binding.getCredentials().get("bucket"); From a5c4e089e1581bd8943c7c6d2195d69fc674423e Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Tue, 5 May 2026 12:19:10 +0200 Subject: [PATCH 5/9] fixes --- .../01-40-fast-prototyping-app-push.md | 111 +++++++++++++----- 1 file changed, 83 insertions(+), 28 deletions(-) diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index 7bf57f860..f84fb8b58 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -2,13 +2,14 @@ This tutorial shows how to deploy a single-container application to SAP BTP Kyma runtime in one CLI command using `kyma app push`, then evolve it into an automated GitHub Actions CD pipeline. No YAML hand-crafting, no container registry setup, no CI/CD pipeline to configure upfront — just code → deploy → iterate. -It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET), need BTP service bindings (e.g., Object Store), and want a clear path from local development to automated CD — all without writing a Dockerfile. +It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET) and want a clear path from local development to automated CD — all without writing a Dockerfile. > For lightweight event-driven workloads where you want zero container knowledge, see [Fast Prototyping With Serverless Functions](01-50-fast-prototyping-serverless-functions.md). ## Prerequisites - [Kyma CLI](https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-cli?locale=en-US#install-kyma-cli) installed. +- An [SAP BTP Kyma runtime](https://help.sap.com/docs/btp/sap-business-technology-platform/kyma-environment) provisioned in your subaccount. - The following [Kyma modules enabled](https://help.sap.com/docs/btp/sap-business-technology-platform/enable-and-disable-kyma-module#adding-a-kyma-module) on your runtime: - **Istio** (enabled by default) — service mesh and networking - **API Gateway** (enabled by default) — external exposure via APIRule @@ -18,10 +19,12 @@ It is a good fit when you have an app in any language supported by [Cloud Native ## Step 1: Create Your App -For this example, use a Spring Boot application that exposes a REST API for managing movies, storing data in BTP Object Store: +For this example, use a Spring Boot application that exposes a REST API for managing movies, storing data in BTP Object Store. A ready-to-use version of this application is available in the [`examples/movies-api`](../../../examples/movies-api) folder. + +To build the application from scratch: ```bash -mkdir my-prototype && cd my-prototype +mkdir "movies-rest" && cd "movies-rest" ``` Create the Maven project structure: @@ -126,6 +129,9 @@ package com.example.movies; import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; +import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; @@ -134,22 +140,41 @@ import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import java.net.URI; +import java.util.List; import java.util.Map; @Configuration public class ObjectStoreConfig { + private static final Logger log = LoggerFactory.getLogger(ObjectStoreConfig.class); + @Bean public S3Client s3Client() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + List allBindings = accessor.getServiceBindings(); + + log.info("SERVICE_BINDING_ROOT = {}", System.getenv("SERVICE_BINDING_ROOT")); + log.info("Found {} service binding(s):", allBindings.size()); + for (ServiceBinding b : allBindings) { + log.info(" - name={}, serviceName={}, servicePlan={}, tags={}, keys={}", + b.getName().orElse("(none)"), + b.getServiceName().orElse("(none)"), + b.getServicePlan().orElse("(none)"), + b.getTags(), + b.getKeys()); + } + + ServiceBinding binding = allBindings.stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() - .orElseThrow(() -> new IllegalStateException("No Object Store binding found")); + .orElseThrow(() -> new IllegalStateException("No matching Object Store binding found")); Map creds = binding.getCredentials(); + log.info("Credentials keys: {}", creds.keySet()); + return S3Client.builder() .region(Region.of((String) creds.get("region"))) - .endpointOverride(URI.create((String) creds.get("endpoint"))) + .endpointOverride(URI.create("https://" + creds.get("host"))) .credentialsProvider(StaticCredentialsProvider.create( AwsBasicCredentials.create( (String) creds.get("access_key_id"), @@ -159,8 +184,9 @@ public class ObjectStoreConfig { @Bean public String bucketName() { - ServiceBinding binding = new DefaultServiceBindingAccessor().getServiceBindings().stream() - .filter(b -> b.getTags().contains("objectstore")) + ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); + ServiceBinding binding = accessor.getServiceBindings().stream() + .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() .orElseThrow(); return (String) binding.getCredentials().get("bucket"); @@ -228,7 +254,11 @@ public class MovieController { @GetMapping @Operation(summary = "List all movies") public List list() throws IOException { - ListObjectsV2Response response = s3.listObjectsV2(b -> b.bucket(bucket).prefix("movies/")); + ListObjectsV2Request request = ListObjectsV2Request.builder() + .bucket(bucket) + .prefix("movies/") + .build(); + ListObjectsV2Response response = s3.listObjectsV2(request); return response.contents().stream() .map(obj -> getMovie(obj.key())) .toList(); @@ -243,7 +273,7 @@ public class MovieController { @PostMapping @ResponseStatus(HttpStatus.CREATED) @Operation(summary = "Create a new movie") - public Movie create(@RequestBody Movie movie) throws Exception { + public Movie create(@org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(String.valueOf(System.currentTimeMillis())); putMovie(saved); return saved; @@ -251,7 +281,7 @@ public class MovieController { @PutMapping("/{id}") @Operation(summary = "Update an existing movie") - public Movie update(@PathVariable String id, @RequestBody Movie movie) throws Exception { + public Movie update(@PathVariable String id, @org.springframework.web.bind.annotation.RequestBody Movie movie) throws Exception { Movie saved = movie.withId(id); putMovie(saved); return saved; @@ -261,18 +291,30 @@ public class MovieController { @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Delete a movie") public void delete(@PathVariable String id) { - s3.deleteObject(b -> b.bucket(bucket).key("movies/" + id + ".json")); + DeleteObjectRequest request = DeleteObjectRequest.builder() + .bucket(bucket) + .key("movies/" + id + ".json") + .build(); + s3.deleteObject(request); } private void putMovie(Movie movie) throws Exception { byte[] json = mapper.writeValueAsBytes(movie); - s3.putObject(b -> b.bucket(bucket).key("movies/" + movie.id() + ".json") - .contentType("application/json"), RequestBody.fromBytes(json)); + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucket) + .key("movies/" + movie.id() + ".json") + .contentType("application/json") + .build(); + s3.putObject(request, software.amazon.awssdk.core.sync.RequestBody.fromBytes(json)); } private Movie getMovie(String key) { try { - byte[] data = s3.getObject(b -> b.bucket(bucket).key(key)).readAllBytes(); + GetObjectRequest request = GetObjectRequest.builder() + .bucket(bucket) + .key(key) + .build(); + byte[] data = s3.getObject(request).readAllBytes(); return mapper.readValue(data, Movie.class); } catch (NoSuchKeyException e) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Movie not found"); @@ -299,7 +341,6 @@ apiVersion: services.cloud.sap.com/v1 kind: ServiceInstance metadata: name: object-store-instance - namespace: default spec: serviceOfferingName: objectstore servicePlanName: standard @@ -311,7 +352,6 @@ apiVersion: services.cloud.sap.com/v1 kind: ServiceBinding metadata: name: object-store-binding - namespace: default spec: serviceInstanceName: object-store-instance ``` @@ -337,7 +377,7 @@ One command builds, pushes, and deploys your app — and exposes it externally: ```bash kyma app push \ - --name my-prototype \ + --name movies-rest \ --code-path . \ --container-port 8080 \ --expose \ @@ -408,14 +448,22 @@ The secret is mounted at `/bindings/secret-` (read-only), and `SERVICE_BIN Once your prototype stabilizes, automate deployments on every push using the [`kyma-project/setup-kyma-cli/app-push`](https://github.com/kyma-project/setup-kyma-cli/tree/main/app-push) GitHub Action. -The action wraps the same `kyma app push` command you ran locally — same flags, same behavior: +The action wraps the same `kyma app push` command you ran locally — same flags, same behavior. The workflow uses OIDC to obtain a kubeconfig at runtime — no long-lived credentials need to be stored as secrets: ```yaml -# .github/workflows/deploy.yml -name: Deploy to Kyma +# .github/workflows/deploy-movies-api.yml +name: Deploy movies-api example + +permissions: + id-token: write + contents: read + on: push: - branches: [main] + branches: + - main + paths: + - 'examples/movies-api/**' jobs: deploy: @@ -423,18 +471,25 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: kyma-project/setup-kyma-cli/app-push@v1 + - name: Setup Kyma CLI + uses: kyma-project/setup-kyma-cli@v1.0.1 + + - name: Get kubeconfig + run: kyma alpha kubeconfig generate --audience kyma-cli --output /tmp/kubeconfig.yaml + + - uses: kyma-project/setup-kyma-cli/app-pushv1.0.1 with: - name: my-prototype - code-path: "." + name: movies-rest + code-path: examples/movies-api container-port: "8080" expose: "true" istio-inject: "true" mount-service-binding-secret: object-store-binding - kubeconfig: ${{ secrets.KYMA_KUBECONFIG }} + kubeconfig: /tmp/kubeconfig.yaml + env-from-file: examples/movies-api/.env ``` -Store your Kyma kubeconfig (base64-encoded) as a GitHub repository secret named `KYMA_KUBECONFIG`. Every push to `main` now triggers a fresh build and deploy — no local tooling required. +The workflow triggers only when files under `examples/movies-api/` change. Every matching push to `main` triggers a fresh build and deploy — no local tooling required. ## Summary From 4b0ce8d310907a47f7a3633c44477410e6a70634 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Tue, 5 May 2026 12:22:20 +0200 Subject: [PATCH 6/9] to much logs --- .../01-40-fast-prototyping-app-push.md | 20 +------------------ .../com/example/movies/ObjectStoreConfig.java | 20 +------------------ 2 files changed, 2 insertions(+), 38 deletions(-) diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index f84fb8b58..1c4704597 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -130,8 +130,6 @@ package com.example.movies; import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; @@ -140,37 +138,21 @@ import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import java.net.URI; -import java.util.List; import java.util.Map; @Configuration public class ObjectStoreConfig { - private static final Logger log = LoggerFactory.getLogger(ObjectStoreConfig.class); - @Bean public S3Client s3Client() { ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); - List allBindings = accessor.getServiceBindings(); - - log.info("SERVICE_BINDING_ROOT = {}", System.getenv("SERVICE_BINDING_ROOT")); - log.info("Found {} service binding(s):", allBindings.size()); - for (ServiceBinding b : allBindings) { - log.info(" - name={}, serviceName={}, servicePlan={}, tags={}, keys={}", - b.getName().orElse("(none)"), - b.getServiceName().orElse("(none)"), - b.getServicePlan().orElse("(none)"), - b.getTags(), - b.getKeys()); - } - ServiceBinding binding = allBindings.stream() + ServiceBinding binding = accessor.getServiceBindings().stream() .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() .orElseThrow(() -> new IllegalStateException("No matching Object Store binding found")); Map creds = binding.getCredentials(); - log.info("Credentials keys: {}", creds.keySet()); return S3Client.builder() .region(Region.of((String) creds.get("region"))) diff --git a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java index 51a9bb2af..d7aae8e74 100644 --- a/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java +++ b/examples/movies-api/src/main/java/com/example/movies/ObjectStoreConfig.java @@ -3,8 +3,6 @@ import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; @@ -13,37 +11,21 @@ import software.amazon.awssdk.services.s3.S3Client; import java.net.URI; -import java.util.List; import java.util.Map; @Configuration public class ObjectStoreConfig { - private static final Logger log = LoggerFactory.getLogger(ObjectStoreConfig.class); - @Bean public S3Client s3Client() { ServiceBindingAccessor accessor = DefaultServiceBindingAccessor.getInstance(); - List allBindings = accessor.getServiceBindings(); - - log.info("SERVICE_BINDING_ROOT = {}", System.getenv("SERVICE_BINDING_ROOT")); - log.info("Found {} service binding(s):", allBindings.size()); - for (ServiceBinding b : allBindings) { - log.info(" - name={}, serviceName={}, servicePlan={}, tags={}, keys={}", - b.getName().orElse("(none)"), - b.getServiceName().orElse("(none)"), - b.getServicePlan().orElse("(none)"), - b.getTags(), - b.getKeys()); - } - ServiceBinding binding = allBindings.stream() + ServiceBinding binding = accessor.getServiceBindings().stream() .filter(b -> "objectstore".equals(b.getServiceName().orElse(null))) .findFirst() .orElseThrow(() -> new IllegalStateException("No matching Object Store binding found")); Map creds = binding.getCredentials(); - log.info("Credentials keys: {}", creds.keySet()); return S3Client.builder() .region(Region.of((String) creds.get("region"))) From b26680f6e330f1d0f4b4d31c40e96b25193179c3 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Wed, 6 May 2026 12:09:12 +0200 Subject: [PATCH 7/9] improvements --- .claude/settings.json | 7 ++ CLAUDE.md | 32 ++++++ .../01-40-fast-prototyping-app-push.md | 108 ++++++++---------- 3 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 .claude/settings.json create mode 100644 CLAUDE.md diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000..ff1e89697 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:raw.githubusercontent.com)" + ] + } +} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..528192f15 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,32 @@ +# Documentation review + +When reviewing or editing documentation files (`docs/**/*.md`), load the SAP/Kyma +technical writing rules: + +https://raw.githubusercontent.com/kyma-project/community/refs/heads/main/docs/guidelines/content-guidelines/agentic.md + +Focus on language and mechanics only (Pass 1 and Pass 2 from the loaded rules). +Do not restructure content or change headings. Silently fix typos, grammar, and +formatting issues without asking for confirmation on each change. + +# Documentation standards + +## Style rules + +Load the SAP/Kyma technical writing styleguide as an on-demand skill for all +documentation work: + +https://raw.githubusercontent.com/kyma-project/community/refs/heads/main/docs/guidelines/content-guidelines/agentic.md + +Apply all passes (formatting, language, terminology, and reconciliation) when +reviewing or writing documentation. + +## Documentation structure + +This repository has three documentation tiers: +- `docs/api/` — Auto-generated API reference (do not edit directly) +- `docs/concepts/` — Conceptual overviews (nominal headings, no procedures) +- `docs/tutorials/` — Step-by-step guides (gerund headings, ordered lists for steps) + +When writing new pages, match the structure and tone of existing pages in the +same tier. \ No newline at end of file diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index 1c4704597..81cfe5809 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -2,9 +2,9 @@ This tutorial shows how to deploy a single-container application to SAP BTP Kyma runtime in one CLI command using `kyma app push`, then evolve it into an automated GitHub Actions CD pipeline. No YAML hand-crafting, no container registry setup, no CI/CD pipeline to configure upfront — just code → deploy → iterate. -It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET) and want a clear path from local development to automated CD — all without writing a Dockerfile. +It is a good fit when you have an app in any language supported by [Cloud Native Buildpacks](https://buildpacks.io/) (Java, Node.js, Go, Python, .NET) and want a clear path from local development to a working prototype in the SAP BTP context — all without writing a Dockerfile. -> For lightweight event-driven workloads where you want zero container knowledge, see [Fast Prototyping With Serverless Functions](01-50-fast-prototyping-serverless-functions.md). +> **Note:** For lightweight event-driven workloads where you want zero container knowledge, see [Fast Prototyping With Serverless Functions](01-50-fast-prototyping-serverless-functions.md). ## Prerequisites @@ -15,7 +15,7 @@ It is a good fit when you have an app in any language supported by [Cloud Native - **API Gateway** (enabled by default) — external exposure via APIRule - **BTP Operator** (enabled by default) — manages BTP service instances and bindings - **Docker Registry** ([community module](https://kyma-project.io/external-content/community-modules/docs/user/README.html#quick-install)) — in-cluster container registry for building and storing images (no external registry needed) -- Your SAP BTP subaccount must be **entitled to use the SAP Object Store service** (service plan `standard`). Add the entitlement in the BTP cockpit under *Entitlements* if not already assigned. +- Your SAP BTP subaccount must be entitled to use the SAP Object Store service (service plan `standard`). Add the entitlement in the BTP cockpit under **Entitlements** if not already assigned. ## Step 1: Create Your App @@ -315,7 +315,8 @@ server.port=8080 ## Step 2: Create the BTP Object Store Service Instance and Binding -Create the service instance and binding using the BTP Operator API (provided by the btp-manager module): +The application needs an Object Store service instance secret mounted into the workload. +Create the service instance and binding using the ServiceInstance and ServiceBinding custom resources: ```yaml # service-instance.yaml @@ -351,7 +352,7 @@ Wait for the binding to become ready: kubectl get servicebindings object-store-binding -w ``` -Once the status shows `Ready: True`, a Kubernetes Secret named `object-store-binding` is created in the namespace with the Object Store credentials. +Once the status shows `Ready: True`, a Kubernetes Secret named `object-store-binding` is created in the namespace with the Object Store credentials. This secret is mounted to the application workload as part of `kyma app push` command execution. ## Step 3: Deploy @@ -376,65 +377,48 @@ JAVA_TOOL_OPTIONS=-XX:ReservedCodeCacheSize=40M -XX:MaxMetaspaceSize=80M -Xss512 ``` What happens under the hood: -1. Source code is built into a container image using [Cloud Native Buildpacks](https://buildpacks.io/) (Paketo) -2. Image is pushed to the in-cluster docker-registry -3. A Deployment, Service, and APIRule are created -4. The BTP Object Store binding secret is mounted at `/bindings/secret-object-store-binding` -5. `SERVICE_BINDING_ROOT=/bindings` environment variable is set automatically -> No Dockerfile required. Buildpacks detect `pom.xml` and automatically build a Java application with the correct JDK. The same approach works for Node.js, Go, Python, .NET, and more. +1. Source code is built into a container image using [Cloud Native Buildpacks](https://buildpacks.io/) (Paketo). +2. Image is pushed to the in-cluster docker-registry. +3. A Deployment, Service, and APIRule are created. +4. The BTP Object Store binding secret is mounted at `/bindings/secret-object-store-binding`. +5. `SERVICE_BINDING_ROOT=/bindings` environment variable is set automatically. -## Step 4: Verify +> **Note:** No Dockerfile required. Buildpacks detect `pom.xml` and automatically build a Java application with the correct JDK. The same approach works for Node.js, Go, Python, .NET, and more. +> +> If you need more control over the image build, `kyma app push` also supports: +> - `--dockerfile ` — build the image from your own Dockerfile instead of using Buildpacks. +> - `--image ` — skip the build entirely and deploy a pre-built image already pushed to a registry. -The command outputs the external URL of your app. Test the CRUD operations: +## Step 4: Verify -```bash -# Health check -curl https:///health -# {"status":"UP"} +The OpenAPI specification is available at `https:///v3/api-docs` and the interactive Swagger UI at `https:///swagger-ui.html`. +Use the Swagger UI to test the CRUD operations. -# Create a movie -curl -X POST https:///movies \ - -H "Content-Type: application/json" \ - -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott"}' -# {"id":"1714900000000","title":"Blade Runner","year":1982,"director":"Ridley Scott"} -# List all movies -curl https:///movies +## Evolution: Move to GitHub Actions CD -# Get a movie by ID -curl https:///movies/ +Once your prototype stabilizes, automate deployments. +Push the code to a GitHub repository, for example `https://github.com/acme/movies-rest`, and authorize the repository's GitHub Actions workflows to apply changes in the target cluster. -# Update a movie -curl -X PUT https:///movies/ \ - -H "Content-Type: application/json" \ - -d '{"title":"Blade Runner","year":1982,"director":"Ridley Scott","rating":8.1}' +To authorize the repository, run: -# Delete a movie -curl -X DELETE https:///movies/ +```bash +kyma alpha authorize repository \ + --client-id my-client-id-for-gh-action \ + --cluster-wide \ + --clusterrole edit \ + --repository acme/movies-rest ``` -The OpenAPI specification is available at `https:///v3/api-docs` and the interactive Swagger UI at `https:///swagger-ui.html`. - -## BTP Service Bindings +> **Note:** Use the most restrictive ClusterRole that satisfies your workflow's needs — `edit` is used here for simplicity, but consider a narrower role. You can also limit authorization to a specific workflow, branch, or environment by passing additional required OIDC claims with `--require-claim`. Run `kyma alpha authorize repository --help` for details. -The `--mount-service-binding-secret` flag mounts a BTP service instance secret into your workload following the [Service Binding Specification](https://servicebinding.io/): +Now you can automate deployments on every push to the main branch using the [`kyma-project/setup-kyma-cli/app-push`](https://github.com/kyma-project/setup-kyma-cli/tree/main/app-push) GitHub Action. -1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit -2. Create a service binding — this produces a Kubernetes Secret with credentials -3. Pass the secret name to `--mount-service-binding-secret` - -The secret is mounted at `/bindings/secret-` (read-only), and `SERVICE_BINDING_ROOT=/bindings` is set automatically. Your application reads credentials from the mounted path. - -## Evolution: Move to GitHub Actions CD - -Once your prototype stabilizes, automate deployments on every push using the [`kyma-project/setup-kyma-cli/app-push`](https://github.com/kyma-project/setup-kyma-cli/tree/main/app-push) GitHub Action. - -The action wraps the same `kyma app push` command you ran locally — same flags, same behavior. The workflow uses OIDC to obtain a kubeconfig at runtime — no long-lived credentials need to be stored as secrets: +The action wraps the same `kyma app push` command you ran locally — same flags, same behavior. The workflow obtains cluster access using a GitHub OIDC token — no long-lived credentials are involved. The only values stored as secrets are the API server URL and CA certificate, which are not sensitive credentials but rather connection details needed to reach the cluster. ```yaml -# .github/workflows/deploy-movies-api.yml -name: Deploy movies-api example +name: Deploy permissions: id-token: write @@ -444,8 +428,6 @@ on: push: branches: - main - paths: - - 'examples/movies-api/**' jobs: deploy: @@ -454,24 +436,32 @@ jobs: - uses: actions/checkout@v4 - name: Setup Kyma CLI - uses: kyma-project/setup-kyma-cli@v1.0.1 + uses: kyma-project/setup-kyma-cli@v1.1.0 - - name: Get kubeconfig - run: kyma alpha kubeconfig generate --audience kyma-cli --output /tmp/kubeconfig.yaml + - 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 }}" # fetch from secure secret store, i.e., Vault or GitHub secrets + ca-crt: "${{ secrets.CA_CRT }}" # fetch from secure secret store, i.e., Vault or GitHub secrets + id-token-auto-refresh: "true" - - uses: kyma-project/setup-kyma-cli/app-pushv1.0.1 + - uses: kyma-project/setup-kyma-cli/app-push@v1.1.0 with: name: movies-rest - code-path: examples/movies-api + code-path: . # relative path of the source code container-port: "8080" expose: "true" istio-inject: "true" mount-service-binding-secret: object-store-binding - kubeconfig: /tmp/kubeconfig.yaml - env-from-file: examples/movies-api/.env + kubeconfig: "${{ steps.oidc.outputs.kubeconfig }}" + env-from-file: .env # relative path of the .env file + append-output-path: /swagger-ui.html + ``` -The workflow triggers only when files under `examples/movies-api/` change. Every matching push to `main` triggers a fresh build and deploy — no local tooling required. +Every push to `main` triggers a fresh build and deploy — no local tooling required. ## Summary From 37e9c4406054dd15e0324d62df5837f4ca186a16 Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Wed, 6 May 2026 12:21:36 +0200 Subject: [PATCH 8/9] screenshot --- docs/assets/app-push-gh-action-summary.png | Bin 0 -> 217620 bytes .../01-40-fast-prototyping-app-push.md | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 docs/assets/app-push-gh-action-summary.png diff --git a/docs/assets/app-push-gh-action-summary.png b/docs/assets/app-push-gh-action-summary.png new file mode 100644 index 0000000000000000000000000000000000000000..17ec2ab370756b3cf47a56a57841b436e46592c1 GIT binary patch literal 217620 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 Q1pcX?(frTr)7O9he^T`HPyhe` literal 0 HcmV?d00001 diff --git a/docs/user/tutorials/01-40-fast-prototyping-app-push.md b/docs/user/tutorials/01-40-fast-prototyping-app-push.md index 81cfe5809..314fdca97 100644 --- a/docs/user/tutorials/01-40-fast-prototyping-app-push.md +++ b/docs/user/tutorials/01-40-fast-prototyping-app-push.md @@ -463,6 +463,8 @@ jobs: Every push to `main` triggers a fresh build and deploy — no local tooling required. +![GitHub Actions deploy workflow summary showing a successful deploy job and the application URL](../../assets/app-push-gh-action-summary.png) + ## Summary With `kyma app push` you go from source code to a running, externally accessible application with BTP service bindings in a single command. The same deployment can then be moved into a GitHub Actions workflow with zero code changes — just copy the flags into the action inputs. From 7ea007eb4e143cf078e4752c8a6e70ba4f6e465e Mon Sep 17 00:00:00 2001 From: kwiatekus Date: Thu, 7 May 2026 16:03:07 +0200 Subject: [PATCH 9/9] skip serverless prototyping tutorial --- ...0-fast-prototyping-serverless-functions.md | 103 ------------------ 1 file changed, 103 deletions(-) delete mode 100644 docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md diff --git a/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md b/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md deleted file mode 100644 index 313386a01..000000000 --- a/docs/user/tutorials/01-50-fast-prototyping-serverless-functions.md +++ /dev/null @@ -1,103 +0,0 @@ -# Fast Prototyping on SAP BTP Kyma: Serverless Functions - -This tutorial shows how to deploy a serverless function to SAP BTP Kyma runtime with BTP service bindings using the CLI, then evolve it into a fully self-managed application by ejecting to plain Kubernetes manifests. No Dockerfile, no image registry, no Deployment manifests — just write a function and deploy. - -It is a good fit when you're building a lightweight API, webhook handler, or event processor and want the fastest path from code to a running workload with BTP service bindings (e.g., Object Store, XSUAA, HANA Cloud) — while keeping an escape hatch to "eject" into standard Kubernetes resources later. - -> For multi-language apps or when you want buildpack-based deployments with a GitHub Actions CD path, see [Fast Prototyping With App Push](01-40-fast-prototyping-app-push.md). - -## Prerequisites - -Install the Kyma CLI and enable the serverless module: - -```bash -# Install Kyma CLI (macOS/Linux) -curl -fsSL https://get.kyma.io | bash - -# Enable the serverless module -kyma module add serverless --default-config-cr -``` - -## Step 1: Scaffold a Function - -```bash -mkdir my-function && cd my-function - -kyma function init --runtime nodejs22 -``` - -This creates a local `handler.js` and `package.json`. Edit the handler to use the BTP Object Store binding: - -```javascript -// handler.js -const fs = require('fs'); - -module.exports = { - main: async function (event, context) { - // Access BTP Object Store via mounted service binding - const bindingPath = '/bindings/object-store'; - try { - const creds = JSON.parse(fs.readFileSync(`${bindingPath}/credentials`, 'utf8')); - return { statusCode: 200, body: JSON.stringify({ endpoint: creds.endpoint }) }; - } catch (err) { - return { statusCode: 500, body: JSON.stringify({ error: err.message }) }; - } - } -}; -``` - -## Step 2: Deploy - -Deploy the function with the BTP Object Store binding mounted: - -```bash -kyma function create my-function \ - --secret-mount object-store-binding=/bindings/object-store -``` - -The serverless module builds and runs the function. No container image, no registry, no Deployment manifest. - -## Step 3: Verify - -Check the function status and invoke it: - -```bash -kyma function get my-function - -# Port-forward to test locally -kubectl port-forward svc/my-function 8080:80 -curl http://localhost:8080 -# {"endpoint":"https://..."} -``` - -## BTP Service Bindings - -The `--secret-mount` flag mounts a BTP service instance secret into your function following the [Service Binding Specification](https://servicebinding.io/): - -1. Create a BTP service instance (e.g., Object Store) via the BTP Operator module or SAP BTP cockpit -2. Create a service binding — this produces a Kubernetes Secret with credentials -3. Pass the secret name and mount path to `--secret-mount` in the format `SECRET_NAME=MOUNT_PATH` - -Your function reads credentials from the mounted path at runtime. - -## Evolution: Eject to Kubernetes Manifests - -When your function outgrows the serverless model — you need custom resource limits, sidecar containers, or want to manage deployment with Helm/Kustomize — eject it: - -```bash -kyma function eject my-function --output-dir ./k8s-manifests -``` - -This generates plain Kubernetes YAML (Deployment, Service, ConfigMap with your source) in `./k8s-manifests/`. From here you fully own the deployment lifecycle: - -- Add it to a Helm chart -- Deploy with `kubectl apply` -- Wire it into any CI/CD pipeline (GitHub Actions, Tekton, ArgoCD) - -The function runtime is preserved — your code stays exactly the same. You just moved from "managed by Serverless module" to "managed by you." - -## Summary - -With `kyma function create` you go from a handler function to a running workload with BTP service bindings — zero container knowledge required. When your needs evolve, `kyma function eject` gives you full ownership of standard Kubernetes manifests without rewriting your application code. - -This is a stepping stone, not a dead end. Start fast, evolve at your own pace.