Technology Blog Posts by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
DenisDuev
Product and Topic Expert
Product and Topic Expert
1,408

Abstract

The SAP Job Scheduling service can be consumed both from the SAP BTP, Cloud Foundry environment and the SAP BTP, Kyma runtime. You may have seen the blogs about Cloud Foundry (CF) - if not, you can find them in the Overview of Blogs.

What are the differences between using the Job Scheduling service for CF and for Kyma:

  • The way you provision the service instance
  • The way you bind the service instance to your application
  • Adding permissions to your user in the BTP cockpit to access the Job Scheduling service dashboard

In addition, you will learn:

  • How to use a Dockerfile to build a Docker image for your Node.js app
  • How to publish this image to a Docker registry
  • How to define a Kubernetes YAML file with everything needed to deploy your solution - including resources like ServiceInstance, ServiceBinding, APIRule

Prerequisites 📋

  • You have enabled the Kyma environment.
  • You have entitlements and quota for the Job Scheduling service.
  • kubectl & kubelogin
  • docker (or podmanreplace "docker" with "podman" in the commands below if you choose this option)
  • A registration on Docker Hub (or some other Docker repository)

Here is what the file structure will look like at the end:

kyma-part-1/
├── Dockerfile
├── manifest.yaml
├── package.json
└── server.js 

 

Steps 🛠

1. Application 📦

We will start by preparing our application for deployment in Kyma.

We can reuse one of the applications provided in the tutorials for Cloud Foundry.

We define our dependencies in package.json:

{
  "main": "server.js",
  "dependencies": {
    "express": "^4.16.3"
  }
}

We define our endpoint logic in server.js using the express library:

const express = require('express');
const app = express();

app.get('/runjob', function(req, res){
   console.log('==> [APP JOB LOG] Job is running . . .');
   res.send('Finished job');
});

const port = process.env.PORT || 3000;
app.listen(port, function(){
   console.log('listening');
})

2. Build and publish a Docker image 🐳

In CF, we've defined a manifest file and used cf push to deploy it to the platform. In Kubernetes, we have one additional step. We need to prepare a Docker image before applying our configurations to the cluster.

2.1 Create a Dockerfile 📄

# Use NodeJS base image
FROM node:20

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies by copying package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install

# Setting env variables
ENV PORT 80

# Copy app source
COPY . .

# Bind the port on which a container will listen for traffic
EXPOSE 80

# Define the Docker image's behavior at runtime
CMD ["npm","run","start"]

2.2 Build a Docker image 🔨

docker build . -t <your-user>/jobapp:part1

2.3 Create a repository on Docker Hub 🗂

These instructions are for Docker Hub, but you can use any other Docker repository you want.

We need this repository to upload the image we've build in the previous step.

  1. Open Docker Hub.
  2. After logging in, go to the Repositories tab.
  3. Choose Create Repository and give it a name, for example jobapp.
  4. Choose Create.

dockerhub-create-repo.png

2.4 Upload the image to a Docker repository ⬆️

1. Log in to Docker Hub:

docker login -u <your-user>

Alternatively: podman login docker.io -u <your-user>

2. Push the image to your Docker registry:

docker push <your-user>/jobapp:part1

Alternatively:  podman push jobapp:part1 <your-user>/jobapp:part1

docker-push.png

3. Apply to Kyma cluster ☁️

In order to work with Kyma (which is in fact, a Kubernetes cluster with additional custom resource definitions), we need a Kubeconfig to authenticate and the kubectl CLI.

3.1 Download and set up Kubeconfig 📥

1. Open the SAP BTP cockpit.

2. Under your subaccount, go to Overview, and find the section Kyma Environment.

3. Open the KubeconfigURL link. This will download the Kubeconfig file on your local PC.

kyma-cockpit.png

4. Then open your terminal (Mac, Linux):

export KUBECONFIG=<location of the downloaded file>

For windows use: Powershell: $env:KUBECONFIG = "…\kubeconfig.yaml", to verify: echo $env:KUBECONFIG 

CMD: set KUBECONFIG=…\kubeconfig.yaml, to verify: echo %KUBECONFIG%

3.2 Create a namespace 🏷

It's a good practice to use separate namespaces, which is why we will create one for this exercise.

kubectl create namespace jobapp-part1

3.3 Create manifest.yaml 📜

The manifest.yaml is like the mtad.yaml (MultiTarget Application), but for Kubernetes.

This YAML file contains all configurations for the Kyma cluster to deploy our application, expose an endpoint, create a service instance and bindings, and mount them to the deployment of our application.

Note that you need to fill:

image: <your-username>/jobapp:part1
(...)
host: jobapp-part1-<your-suffix>.<kyma-apps-domain>

You can find help as comments in the manifest.yaml:

# defining the service instance
apiVersion: services.cloud.sap.com/v1
kind: ServiceInstance
metadata:
  # this will be the name of your service instance
  name: jobscheduler-instance
  labels:
    app.kubernetes.io/name: jobscheduler-instance
  annotations: {}
  namespace: jobapp-part1
spec:
  # the values supplied here are the ones from the Service Marketplace
  # serviceOfferingName is the "Technical name" of the Job Scheduling service
  serviceOfferingName: jobscheduler
  servicePlanName: standard
---
# defining the service binding
apiVersion: services.cloud.sap.com/v1
kind: ServiceBinding
metadata:
  # this will be the name of your service binding
  name: jobscheduler-binding
  labels:
    app.kubernetes.io/name: jobscheduler-binding
  annotations: {}
  namespace: jobapp-part1
spec:
  # specify the name of the service-instance
  serviceInstanceName: jobscheduler-instance
---
apiVersion: v1
kind: Service
metadata:
  namespace: jobapp-part1
  name: jobapp
  labels:
    run: jobapp
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: http
  selector:
    app: jobapp
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: jobapp-part1
  name: jobapp
  labels:
    app: jobapp
    version: nodejs
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jobapp
      version: nodejs
  template:
    metadata:
      labels:
        app: jobapp
        version: nodejs
    spec:
      containers:
        - name: jobapp
          # replace <your-username> with your Docker Hub image namespace/user
          image: <your-username>/jobapp:part1
          imagePullPolicy: Always
          ports:
            - containerPort: 80
          env:
            - name: SERVICE_BINDING_ROOT
              value: /bindings
          # this mounts a volume from the service-binding    
          volumeMounts:
            - mountPath: /bindings/jobscheduler-instance
              name: jobscheduler-volume
              readOnly: true
      volumes:
          # creates volume for the binding secret
        - name: jobscheduler-volume
          secret:
            defaultMode: 420
            secretName: jobscheduler-binding
---
apiVersion: gateway.kyma-project.io/v1beta1
kind: APIRule
metadata:
  namespace: jobapp-part1
  name: jobapp
  labels:
    app.kubernetes.io/name: jobapp
spec:
  gateway: kyma-gateway.kyma-system.svc.cluster.local
  rules:
    - accessStrategies:
        - handler: allow
          config: {}
      methods:
        - GET
        - POST
        - PUT
        - DELETE
      path: /.*
  # host is the address that your app will be accessible over
  # you can get <kyma-apps-domain> from the APIServerURL in the cockpit by removing the https://api or
  # by executing:
  # kubectl config view --minify --output 'jsonpath={.clusters[0].cluster.server}' | awk -F'api.' '{print $2}'
  # <your-suffix> can be whatever you want - as long the the DNS is unique
  host: jobapp-part1-<your-suffix>.<kyma-apps-domain>
  service:
    name: jobapp
    port: 80

3.4 Apply changes to the cluster 🚀

kubectl apply -f manifest.yaml

kubectl-appy.png

4. Validate the application

Now that your application is deployed, it's time to test it.

Open your endpoint in the browser (for example, https://jobapp-part1-<your-suffix>.<kyma-apps-domain>/runjob).

You should have specified this URL in the manifest.yaml (host).

test-app.png

5. Testing the Job Scheduling service 🕒

5.1 Permissions for the Job Scheduling service dashboard 🔑

To view the dashboard, your user has to have the SAP_Job_Scheduling_Service_Admin role assigned from the SAP BTP cockpit.

  1. In your subaccount, from the Security menu, choose Role Collections.
  2. Choose Create.
  3. In the dialog, add a name SAP Job Scheduling Service Admin and description Assign it to access Job Scheduling Service Dashboard and manage jobs, then choose Create.
  4. Choose the newly created role collection SAP_Job_Scheduling_Service_Admin.
  5. Choose Edit.
  6. In the Roles tab, find the SAP_Job_Scheduling_Service_Admin Role Name, mark it in the list, and choose Add.
  7. Choose Save on the role collection.
  8. From the Security menu, go to Users.
  9. Find your user, select it, then choose Assign Role Collection.
  10. From the list, find SAP_Job_Scheduling_Service_Admin, mark it, and then choose Assign Role Collection.

kyma-jobscheduling-roles.gif

5.2 Link to the dashboard 🔗

To find the dashboard URL:

1. Go to Instances and Subscriptions in the SAP BTP cockpit.

2. Choose the "jobscheduler" service instance.

3. Choose View Dashboard:

dashboard.png

5.3 Create job 📝

  1. From the Job Scheduling service dashboard, choose Jobs in the left-hand menu.
  2. Then choose Create Job.
  3. In the creation dialog, specify the required information:
    • Name - this is the technical name, for example: jobapp_get_runjob 
    • Action - this is the endpoint of your service that we want to call (from step 4. Validate the application) https://jobapp-part1-<your-suffix>.<kyma-apps-domain>/runjob 
    • HTTP Method - in our case GET is correct
  4. Choose Save and the dialog is closed.
  5. Then choose the Name of the newly created job. The Overview page opens.
  6. From the left-hand menu, choose Schedules. Then choose Create Schedule.
  7. For "value", enter now and choose Save. This means that the scheduler will be executed only one time - now.
  8. Choose the Description of the newly created schedule. The Overview page opens.
  9. From the left-hand menu, choose Run Logs to see the executions for this schedule.
  10. If you choose Runlog ID, you can see more details about the specific run (execution).

create-job-kyma.gif

🎉 That's it! 🎉

🥳 You have done it - you have successfully called your newly developed Kyma application using the SAP Job Scheduling service.


6. Cleanup

After you are ready, you can delete all of your resources using:

kubectl delete -f manifest.yaml

so that you are ready for our 🔝 next tutorial 🔝.

kubectl-delete.png

 

Troubleshooting🛠

Q: Error on kubectl apply?

kubectl-apply-no-namespace.png

A: Have you created your namespace? If not, use:

kubectl create namespace jobapp-part1

Q: kubectl apply is successful, but the application is not working?

A: You can open the Kyma UI to validate that all resources are correctly provisioned.

OR You can run the following command and check the READY field in the output:

kubectl -n jobapp-part1 get all,serviceinstance,servicebindings,APIRule

kubectl-get-all.png

Q: Is my service instance created?

A: You can check that using the 

kubectl -n jobapp-part1 describe serviceinstance.services.cloud.sap.com/jobscheduler-instance or in the Kyma 

or in the UI:

kyma-ui-service-instance-created.png

Q: How to remove my resources?

A: Use CLI:

kubectl delete -f manifest.yaml

Or remove them manually in the Kyma UI.


Q: When I call the application endpoint I get: no healthy upstream

Option 1: Check your pods, especially your Docker image - have you added your username?

  1. kubectl -n jobapp-part1 get pods
  2. kubectl -n jobapp-part1 describe jobapp-<unique-id-from-previous-step>

Option 2: Do you have enough quota for the Job Scheduling service? Run:

kubectl -n jobapp-part1 describe serviceinstance.services.cloud.sap.com/jobscheduler-instance

If you see something like the following, your quota is not enough and you need to increase it.

Status:
  Conditions:
    Last Transition Time:  2024-09-13T10:07:26Z
    Message:               BrokerError:, Status: 400, Description: Subaccount quota limit for specified service plan has exceeded. Please contact service administrator.
    Observed Generation:   1
    Reason:                CreateInProgress
    Status:                False
    Type:                  Succeeded
    Last Transition Time:  2024-09-13T10:07:26Z
    Message:
    Reason:                NotProvisioned