|
| 1 | +# Scheduling function runs |
| 2 | + |
| 3 | +If you are deploying OpenFaaS to [Kubernetes][k8s], then we can easily run functions as cron jobs using the aptley named [Cron Job resource][k8scron]. |
| 4 | + |
| 5 | +We assume that you have used the [recommended install of `faas-netes`][faasdeploy] which menas that you have OpenFaaS deployed into two namespaces: |
| 6 | + |
| 7 | +1. `openfaas` for the core componentes (ui, gateway, etc) |
| 8 | +2. `openfaas-fn` for the function deployments |
| 9 | + |
| 10 | +## Simple Cron Job |
| 11 | + |
| 12 | +For this example, we use the [sample `nodeinfo` function][nodeinfo], which can be deployed using this stack file |
| 13 | + |
| 14 | +```yaml |
| 15 | +# stack.yaml |
| 16 | +provider: |
| 17 | + name: faas |
| 18 | + gateway: http://gateway.openfaas.local |
| 19 | + |
| 20 | +functions: |
| 21 | + nodeinfo: |
| 22 | + lang: dockerfile |
| 23 | + handler: node main.js |
| 24 | + image: functions/nodeinfo:latest |
| 25 | + skip_build: true |
| 26 | +``` |
| 27 | +
|
| 28 | +and the cli |
| 29 | +
|
| 30 | +```yaml |
| 31 | +$ faas deploy |
| 32 | +``` |
| 33 | + |
| 34 | +We can then define a Kubernetes cron job to call this function every minute using this manifest file: |
| 35 | + |
| 36 | +```yaml |
| 37 | +# node-cron.yaml |
| 38 | +apiVersion: batch/v1beta1 |
| 39 | +kind: CronJob |
| 40 | +metadata: |
| 41 | + name: nodeinfo |
| 42 | + namespace: openfaas |
| 43 | +spec: |
| 44 | + schedule: "*/1 * * * *" |
| 45 | + concurrencyPolicy: Forbid |
| 46 | + successfulJobsHistoryLimit: 1 |
| 47 | + failedJobsHistoryLimit: 3 |
| 48 | + jobTemplate: |
| 49 | + spec: |
| 50 | + template: |
| 51 | + spec: |
| 52 | + containers: |
| 53 | + - name: faas-cli |
| 54 | + image: openfaas/faas-cli:0.6.9 |
| 55 | + args: |
| 56 | + - /bin/sh |
| 57 | + - -c |
| 58 | + - echo "verbose" | ./faas-cli invoke nodeinfo -g http://gateway:8080 |
| 59 | + restartPolicy: OnFailure |
| 60 | +``` |
| 61 | +
|
| 62 | +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 and easy to generize to other functions. |
| 63 | + |
| 64 | +We schedule the job by applying our manifest |
| 65 | + |
| 66 | +```sh |
| 67 | +$ kubectl apply -f node-cron.yaml |
| 68 | +$ kubectl -n=openfaas get cronjob nodeinfo --watch |
| 69 | +NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE |
| 70 | +nodeinfo */1 * * * * False 0 <none> 42s |
| 71 | +nodeinfo */1 * * * * False 1 2s 44s |
| 72 | +nodeinfo */1 * * * * False 0 12s 54s |
| 73 | +nodeinfo */1 * * * * False 1 2s 1m |
| 74 | +nodeinfo */1 * * * * False 0 12s 1m |
| 75 | +``` |
| 76 | + |
| 77 | +Unfortunately, there is no one-line command in `kubectl` for getting the logs from a cron job. Kuberenets creates new Job objects for each run of the CronJob, so we can look up that last run of our CronJob using |
| 78 | + |
| 79 | +```sh |
| 80 | +$ kubectl -n openfaas get job |
| 81 | +NAME DESIRED SUCCESSFUL AGE |
| 82 | +nodeinfo-1529226900 1 1 6s |
| 83 | +``` |
| 84 | + |
| 85 | +We can use this to then get the output logs |
| 86 | + |
| 87 | +```sh |
| 88 | +$ kubectl -n openfaas logs -l "job-name=nodeinfo-1529226900" |
| 89 | +Hostname: nodeinfo-6fffdb4446-57mzn |
| 90 | +
|
| 91 | +Platform: linux |
| 92 | +Arch: x64 |
| 93 | +CPU count: 1 |
| 94 | +Uptime: 997420 |
| 95 | +[ { model: 'Intel(R) Xeon(R) CPU @ 2.20GHz', |
| 96 | + speed: 2199, |
| 97 | + times: |
| 98 | + { user: 360061300, |
| 99 | + nice: 2053900, |
| 100 | + sys: 142472900, |
| 101 | + idle: 9425509300, |
| 102 | + irq: 0 } } ] |
| 103 | +{ lo: |
| 104 | + [ { address: '127.0.0.1', |
| 105 | + netmask: '255.0.0.0', |
| 106 | + family: 'IPv4', |
| 107 | + mac: '00:00:00:00:00:00', |
| 108 | + internal: true }, |
| 109 | + { address: '::1', |
| 110 | + netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', |
| 111 | + family: 'IPv6', |
| 112 | + mac: '00:00:00:00:00:00', |
| 113 | + scopeid: 0, |
| 114 | + internal: true } ], |
| 115 | + eth0: |
| 116 | + [ { address: '10.4.2.40', |
| 117 | + netmask: '255.255.255.0', |
| 118 | + family: 'IPv4', |
| 119 | + mac: '0a:58:0a:04:02:28', |
| 120 | + internal: false }, |
| 121 | + { address: 'fe80::f08e:d8ff:fecc:9635', |
| 122 | + netmask: 'ffff:ffff:ffff:ffff::', |
| 123 | + family: 'IPv6', |
| 124 | + mac: '0a:58:0a:04:02:28', |
| 125 | + scopeid: 3, |
| 126 | + internal: false } ] } |
| 127 | +``` |
| 128 | + |
| 129 | +## Other considerations |
| 130 | + |
| 131 | +This simple example uses the default deployment of OpenFaaS without any authentication. |
| 132 | + |
| 133 | +### Multiple Namespaces |
| 134 | + |
| 135 | +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 accomidate. Fortunately, with Kubernetes DNS, this is simply changing the gateway parameter like this `./faas-cli invoke nodeinfo -g http://gateway.othernamespace:8080` |
| 136 | + |
| 137 | +### Authentication |
| 138 | + |
| 139 | +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 a secret with a file for the username and a separate file for the password, like this |
| 140 | + |
| 141 | +```sh |
| 142 | +$ kubectl -n openfaas create secret generic faas-basic-auth --from-file=./username --from-file=./password |
| 143 | +``` |
| 144 | + |
| 145 | +You could then update the CronJob to login, like this |
| 146 | + |
| 147 | +```yaml |
| 148 | +# nodeauth-cron.yaml |
| 149 | +apiVersion: batch/v1beta1 |
| 150 | +kind: CronJob |
| 151 | +metadata: |
| 152 | + name: nodeinfo-auth |
| 153 | + namespace: openfaas |
| 154 | +spec: |
| 155 | + schedule: "*/1 * * * *" |
| 156 | + concurrencyPolicy: Forbid |
| 157 | + successfulJobsHistoryLimit: 1 |
| 158 | + failedJobsHistoryLimit: 3 |
| 159 | + jobTemplate: |
| 160 | + spec: |
| 161 | + template: |
| 162 | + spec: |
| 163 | + containers: |
| 164 | + - name: faas-cli |
| 165 | + image: openfaas/faas-cli:0.6.9 |
| 166 | + env: |
| 167 | + - name: FAAS_USERNAME |
| 168 | + valueFrom: |
| 169 | + secretKeyRef: |
| 170 | + name: faas-basic-auth |
| 171 | + key: username |
| 172 | + - name: FAAS_PASSWORD |
| 173 | + valueFrom: |
| 174 | + secretKeyRef: |
| 175 | + name: faas-basic-auth |
| 176 | + key: password |
| 177 | + args: |
| 178 | + - /bin/sh |
| 179 | + - -c |
| 180 | + - ./faas-cli login -g http://gateway:8080 -u $FAAS_USERNAME -p $FAAS_PASSWORD |
| 181 | + - echo "verbose" | ./faas-cli invoke nodeinfo -g http://gateway:8080 |
| 182 | + restartPolicy: OnFailure |
| 183 | +``` |
| 184 | + |
| 185 | +[k8s]: https://kubernetes.io/ "Kubernetes" |
| 186 | +[k8scron]: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/ "Kuberenetes CRON Jobs" |
| 187 | +[k8sjob]: https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/ "Kuberenetes Jobs" |
| 188 | +[faasdeploy]: https://github.com/openfaas/faas-netes/tree/master/chart/openfaas#deploy-openfaas |
| 189 | +[nodeinfo]: https://github.com/openfaas/faas/tree/master/sample-functions/NodeInfo |
0 commit comments