Scheduling function runs

Kubernetes

If you are deploying OpenFaaS to Kubernetes, then we can easily run functions as cron jobs using the aptly named Cron Job resource.

We assume that you have used the recommended install of faas-netes which means that you have OpenFaaS deployed into two namespaces:

  1. openfaas for the core components (ui, gateway, etc)
  2. openfaas-fn for the function deployments

Simple Cron Job

For this example we’ll deploy a function which can print system info about the container it’s running in:

  1. faas-cli store deploy nodeinfo

We can then define a Kubernetes cron job to call this function every minute using this manifest file:

  1. # node-cron.yaml
  2. apiVersion: batch/v1beta1
  3. kind: CronJob
  4. metadata:
  5. name: nodeinfo
  6. namespace: openfaas
  7. spec:
  8. schedule: "*/1 * * * *"
  9. concurrencyPolicy: Forbid
  10. successfulJobsHistoryLimit: 1
  11. failedJobsHistoryLimit: 3
  12. jobTemplate:
  13. spec:
  14. template:
  15. spec:
  16. containers:
  17. - name: openfaas-cli
  18. image: ghcr.io/openfaas/faas-cli:latest
  19. imagePullPolicy: IfNotPresent
  20. command:
  21. - /bin/sh
  22. args:
  23. - -c
  24. - echo "verbose" | faas-cli invoke nodeinfo -g http://gateway.openfaas:8080
  25. restartPolicy: OnFailure

You should also update the image to the latest version of the faas-cli available found via the GitHub Container Registry or faas-cli releases page.

The important thing to notice is that we are using a Docker container with the faas-cli to invoke the function. This keeps the job very generic.

We schedule the job by applying our manifest

  1. $ kubectl apply -f node-cron.yaml
  2. $ kubectl -n=openfaas get cronjob nodeinfo --watch
  3. NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
  4. nodeinfo */1 * * * * False 0 <none> 42s
  5. nodeinfo */1 * * * * False 1 2s 44s
  6. nodeinfo */1 * * * * False 0 12s 54s
  7. nodeinfo */1 * * * * False 1 2s 1m
  8. nodeinfo */1 * * * * False 0 12s 1m

Unfortunately, there is no one-line command in kubectl for getting the logs from a cron job. Kubernetes creates new Job objects for each run of the CronJob, so we can look up that last run of our CronJob using

  1. $ kubectl -n openfaas get job
  2. NAME DESIRED SUCCESSFUL AGE
  3. nodeinfo-1529226900 1 1 6s

We can use this to then get the output logs

  1. $ kubectl -n openfaas logs -l "job-name=nodeinfo-1529226900"
  2. Hostname: nodeinfo-6fffdb4446-57mzn
  3. Platform: linux
  4. Arch: x64
  5. CPU count: 1
  6. Uptime: 997420
  7. [ { model: 'Intel(R) Xeon(R) CPU @ 2.20GHz',
  8. speed: 2199,
  9. times:
  10. { user: 360061300,
  11. nice: 2053900,
  12. sys: 142472900,
  13. idle: 9425509300,
  14. irq: 0 } } ]
  15. { lo:
  16. [ { address: '127.0.0.1',
  17. netmask: '255.0.0.0',
  18. family: 'IPv4',
  19. mac: '00:00:00:00:00:00',
  20. internal: true },
  21. { address: '::1',
  22. netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
  23. family: 'IPv6',
  24. mac: '00:00:00:00:00:00',
  25. scopeid: 0,
  26. internal: true } ],
  27. eth0:
  28. [ { address: '10.4.2.40',
  29. netmask: '255.255.255.0',
  30. family: 'IPv4',
  31. mac: '0a:58:0a:04:02:28',
  32. internal: false },
  33. { address: 'fe80::f08e:d8ff:fecc:9635',
  34. netmask: 'ffff:ffff:ffff:ffff::',
  35. family: 'IPv6',
  36. mac: '0a:58:0a:04:02:28',
  37. scopeid: 3,
  38. internal: false } ] }

This example assumes no authentication is enabled on the gateway.

Multiple Namespaces

In this example, I created the CronJob in the same namespace as the gateway. If we deploy the CronJob in a different namespace, then we need to update the job arguments to accommodate. Fortunately, with Kubernetes DNS, this is simply changing the gateway parameter like this ./faas-cli invoke nodeinfo -g http://gateway.othernamespace:8080

Authentication

If you have enabled basic auth on the gateway, then the invoke command will also need to be updated to first login the cli client. Assuming that you have created the basic auth secret as in the Helm install guide

You could then update the CronJob to login, like this:

  1. # nodeauth-cron.yaml
  2. apiVersion: batch/v1beta1
  3. kind: CronJob
  4. metadata:
  5. name: nodeinfo-auth
  6. namespace: openfaas
  7. spec:
  8. schedule: "*/1 * * * *"
  9. concurrencyPolicy: Forbid
  10. successfulJobsHistoryLimit: 1
  11. failedJobsHistoryLimit: 3
  12. jobTemplate:
  13. spec:
  14. template:
  15. spec:
  16. containers:
  17. - name: openfaas-cli
  18. image: ghcr.io/openfaas/faas-cli:latest
  19. env:
  20. - name: USERNAME
  21. valueFrom:
  22. secretKeyRef:
  23. name: basic-auth
  24. key: basic-auth-user
  25. - name: PASSWORD
  26. valueFrom:
  27. secretKeyRef:
  28. name: basic-auth
  29. key: basic-auth-password
  30. command:
  31. - /bin/sh
  32. args:
  33. - -c
  34. - echo -n $PASSWORD | faas-cli login -g http://gateway.openfaas:8080 -u $USERNAME --password-stdin
  35. - echo "verbose" | faas-cli invoke nodeinfo -g http://gateway.openfaas:8080
  36. restartPolicy: OnFailure

Cron Connector

The cron-connector is an OpenFaaS event-connector which can be used to trigger functions on a timed-basis. It makes use of the OpenFaaS REST API, so it is capable of working with all OpenFaaS providers.

Kubernetes

  • Deploy the connector
  1. arkade install cron-connector
  • Now annotate a function with a topic of cron-function and a schedule using a valid CRON expression:
  1. # (Abridged YAML)
  2. functions:
  3. nodeinfo:
  4. image: functions/nodeinfo
  5. skip_build: true
  6. annotations:
  7. topic: cron-function
  8. schedule: "*/5 * * * *"

nodeinfo.yaml

  1. faas-cli deploy -f nodeinfo.yaml
  • Or deploy directly from the store
  1. faas-cli store deploy nodeinfo \
  2. --annotation topic="cron-function" \
  3. --annotation schedule="*/5 * * * *"
  • Now check the logs
  1. kubectl logs -n openfaas-fn deploy/nodeinfo -f

You’ll see the function invoked every 5 minutes as per the schedule.

To stop the invocations, remove the two annotations or remove the cron-connector deployment.

If you would like to explore how to write CRON expressions, then see https://crontab.guru/

faasd

faasd has no concepts of scheduled tasks or cron, but we have a suitable recommendation which you can use with your OpenFaaS cluster. If you deploy a Jenkins master service, then you can use that to manage your scheduled tasks. It will handle distributed locking, concurrency and queueing.

Example usage:

  • Deploy Swarm service for Jenkins using Official Docker Hub image
  • Define a Freestyle job for each scheduled task
  • Add a CRON entry for the schedule
  • Install the OpenFaaS CLI
  • Run faas-cli login --gateway
  • Invoke the function

Here is an example of how to do this with a Pipeline job.

Alternatively see the above cron-connector example.