Set of 'look ma no server' demos to enjoy OpenWhisk
A while ago I was proposed to run a tech lab around the 'serverless' buzzword. By then I was already aware of the concept (I tried AWS Lambda back in 2015) and actually liked it, but to be honest since those experiments I had had very little contact with serverless tech, until Red Hat released some interesting labs (more on this later) and I started again to feel the rush of pushing code and run it live. So… if you haven't tried it, you should!
I'll introduce you to a set of explained simple demos of increasing complexity. I also give some hints to make sense of 'serverless' and 'function as a service' in the real world. This is part 1 of (maybe) 3, other parts (code is already included in folder ./node) will include an Alexa Skill and an integration with AHOI API
In order to run these demos you need either an accessible Openshift environment with around 5GB RAM / 50GB disk / 3 vCPU or a computer at hand with minishift installed and those free resources.
$ minishift version
minishift v1.26.1+1e20f27
Go here for instructions to install minishift.
You'll also need the Openshift CLI, go here for instructions to install it.
In order to follow the guide my suggestion is to clone, fork, download the code. The repo is here.
$ git clone https://github.com/cvicens/openwhisk-demo
$ cd openwhisk-demo
By default I'll assume you're in folder openwhisk-demo
unless otherwise advised.
If you already have an Openshift environment you can skip this. You could also skip this if you want to use the learning area here (maybe you need to make slight changes… honestly I haven't tried but it should work well)
In order to set up our demo, we need to run ./01-setup-minishift.sh
. Please have a look to ./00-environment.sh
to confirm the default values for the minishift profile we're going to create.
Pay special attention to variables MINISHIFT_VM_DRIVER and PLATFORM to make then match your environment!
$ ./01-setup-minishift.sh
After a while should get messages like these...
$ ./01-setup-minishift.sh
Profile 'openwhisk' set as active profile.
No Minishift instance exists. New 'memory' setting will be applied on next 'minishift start'
No Minishift instance exists. New 'cpus' setting will be applied on next 'minishift start'
No Minishift instance exists. New 'vm-driver' setting will be applied on next 'minishift start'
No Minishift instance exists. New 'disk-size' setting will be applied on next 'minishift start'
Add-on 'admin-user' enabled
Add-on 'anyuid' enabled
-- Starting profile 'openwhisk'
-- Check if deprecated options are used ... OK
-- Checking if https://github.com is reachable ... OK
-- Checking if requested OpenShift version 'v3.11.0' is valid ... OK
-- Checking if requested OpenShift version 'v3.11.0' is supported ... OK
...
The server is accessible via web console at:
https://192.168.64.41:8443/console
You are logged in as:
User: developer
Password: <any value>
To login as administrator:
oc login -u system:admin
-- Applying addon 'admin-user':..
-- Applying addon 'anyuid':.
Add-on 'anyuid' changed the default security context constraints to allow pods to run as any user.
Per default OpenShift runs containers using an arbitrarily assigned user ID.
Refer to https://docs.okd.io/latest/architecture/additional_concepts/authorization.html#security-context-constraints and
https://docs.okd.io/latest/creating_images/guidelines.html#openshift-origin-specific-guidelines for more information.
Now please log in to your minishift with the next script.
$ ./02-login-minishift.sh
If you have your own OpenShift environment, don't forget to login in using the
oc
tool... otherwise you'll get this message:You need to log in your Openshift cluster first...
Deploying OpenWhisk on OpenShift means basically applying a template, a one-liner like this.
oc process -f https://git.io/openwhisk-template | oc create -f -
To make it a little easier (I hope) I've prepared a script that creates a project/namespace (by default openwhisk-demo
), deploys OpenWhisk in it, and downloads and sets up the OpenWhisk CLI wsk
in ./bin
So let's do this, please run the script as follows.
Please ignore this error if hit: unable to recognize no matches for kind "CronJob" in version "batch/v2alpha1"
You can also use a local version of the template I fixed, to do so, look for '# Deploying OpenWhisk, choose the remote (default) or local template'
$ ./03-deploy-opewhisk.sh
Now using project "openwhisk-demo" on server "https://master.serverless-e442.openshiftworkshop.com:443".
...
to build a new example application in Ruby.
configmap/whisk.config created
...
alarmprovider-7755754445-hp2hc 0/1 Init:0/2 0 3s
controller-0 0/1 Init:0/2 0 5s
couchdb-0 0/1 ContainerCreating 0 4s
install-catalog-5jfjv 0/1 Init:0/1 0 5s
invoker-0 0/1 Init:0/2 0 4s
nginx-85697b95cf-zkgzl 0/1 Init:0/1 0 3s
...
Finally you should see something like this, it's a list of items you get by invoking wsk list
. It means everything is set up correctly.
Beware that commands are run like this
./bin/wsk -i
becausewsk
is not in your PATH,-i
is needed because we assume you don't have an OpenShift environment using certificates signed by a recognized CA.
./bin/wsk -i list
Entities in namespace: default
packages
/whisk.system/combinators shared
...
actions
/whisk.system/samples/curl private nodejs:6
...
triggers
rules
There are several Javascript and Java examples.
In general demos are divided into two scripts:
- one to deploy the function
- and another one to run it
Let's start with the basics.
The idea is to deploy a function like this one below, file ./node/greeter.js
.
function main(params) {
var name = params.name || 'Guest';
var place = params.place || 'OpenShift Cloud Functions';
return {payload: 'Welcome to ' + place + ', ' + name};
}
To deploy the function you only need to to this.
Pay attention to the
--web
flag, this means we can invoke this action using HTTP
$ ./bin/wsk -i action update --web=true greeter ./node/greeter.js
ok: updated action greeter
The provided script
04-node-action-deploy.sh
makes surewsk
is set up properly but it's not mandatory to use it
There are several way to run our function, using wsk
synchronously/asynchronously, HTTP GET/POST, ...
Calling our function synchronously, --result
instructs to wait for the result.
$ ./bin/wsk -i action invoke --result greeter -p name 'Carlos' -p place 'Lisbon'
{
"payload": "Welcome to Lisbon, Carlos"
}
Same call, but this time in an asynchronous way
$ ./bin/wsk -i action invoke greeter -p name 'Carlos' -p place 'Lisbon'
ok: invoked /_/greeter with id 6c64b7206b5e483fa4b7206b5e483fad
Now to get the result we do as follows.
$ ./bin/wsk -i activation result 6c64b7206b5e483fa4b7206b5e483fad
{
"payload": "Welcome to Lisbon, Carlos"
}
If we want to use HTTP, first we need the URL.
$ ./bin/wsk -i action get greeter --url | awk 'FNR==2{print $1}'
https://openwhisk-openwhisk-demo.apps.serverless-e442.openshiftworkshop.com/api/v1/web/whisk.system/default/greeter
If we store the result in a variable, we can then use curl
for testing.
Pay attention! You need to add '.json' to the URL for the action to return JSON. '.text' would return text, etc. Go here for nice article mentioning web actions and other content types.
$ export WEB_URL=`./bin/wsk -i action get greeter --url | awk 'FNR==2{print $1}'`
$ curl -k --silent -X GET ${WEB_URL}.json?name=Carlos\&place=Madrid
{
"payload": "Welcome to Madrid, Carlos"
}
$ curl -k --silent -d '{"name":"Carlos", "place":"Barcelona"}' -H "Content-Type: application/json" -X POST $WEB_URL.json
{
"payload": "Welcome to Barcelona, Carlos"
}
You can run all these calls with 05-node-action-run.sh
The OpenWhisk Java runtime needs your function to have this exact signature.
public static com.google.gson.JsonObject main(com.google.gson.JsonObject);
Although it's not necessary, as we just said the only requirement is to have a Java class including a method as specified, in this example we're going to use a Maven archetype.
Our first task is to install the archetype
This can also be done by running the script
./06-maven-install-archetype.sh
$ git clone https://github.com/apache/incubator-openwhisk-devtools ./tmp/incubator-openwhisk-devtools
$ cd ./tmp/incubator-openwhisk-devtools/java-action-archetype
$ mvn -DskipTests=true -Dmaven.javadoc.skip=true -B -V clean install
Let's create and deploy a Java function using the archetype as follows
You can use the script
07-maven-action-deploy.sh
to do this task or you can also adapt it to your needs, java package name, artifact ID, etc.
$ export ARTIFACT_ID="demo-function"
$ mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.apache.openwhisk.java \
-DarchetypeArtifactId=java-action-archetype \
-DarchetypeVersion=1.0-SNAPSHOT \
-DgroupId=com.redhat.serverless \
-DartifactId=${ARTIFACT_ID}
$ cd ${ARTIFACT_ID}
$ mvn clean package
After generating and packaging the sample function a jar file should have been generated at ./${ARTIFACT_ID}/target/${ARTIFACT_ID}.jar
Next step is to deploy our function in OpenWhisk, to do so we need the name of the action (in the next example is demo
) the path to the jar file and the fully qualified name of the class that contains our function.
By default when using the archetype
-DgroupId=com.redhat.serverless
means--main com.redhat.serverless.FunctionApp
./bin/wsk -i action update demo ./${ARTIFACT_ID}/target/${ARTIFACT_ID}.jar --main com.redhat.serverless.FunctionApp
Running the action
Running the action is as easy as before.
Again you can use this script
08-maven-action-run.sh
./bin/wsk -i action invoke demo --result
I've taken the code by Philippe Suter and used it in a Java class generated using the archetype I introduced before.
The code of the QR generator class is original from Philippe Suter, and can be found here.
The mechanics are the same as before, the only change is the code of the function itself.
To deploy the function run the deploy script.
$ ./09-maven-action-qr-gen-deploy.sh
...
------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.288 s
[INFO] Finished at: 2018-12-11T19:09:11+01:00
[INFO] Final Memory: 22M/210M
[INFO] ------------------------------------------------------------------------
ok: whisk auth set. Run 'wsk property get --auth' to see the new value.
ok: whisk API host set to openwhisk-openwhisk-demo.apps.serverless-e442.openshiftworkshop.com
ok: updated action qr
To run the action you can either call the action like this...
By adding
| jq -r '.qr' | base64 --decode > qr.png
you can decode the base64 into a proper PNG
$ ./bin/wsk -i action invoke -br qr -p text 'Hola mundo!'
{
"qr": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAABGklEQVR42u3aOxLCIBCAYag8BkdNjsoRLK1A3hBNokWA0fkpHBI+q51lYSfCfjPuAgaDwWCwn2IPkYaKM2nX9ELCxrH4ZFflZumnXYANYmsIkWr+EGIHm8J8ntxgc1l5hM1gNVEWHYJ1vr/BOrBaxHP5+FDrYdezZpi6eHbuhV3PfKKEiCnHQspYfTN7MYV1Za50B1EW8xYGG8akj44rGsnmC4aAjWSpWCw6nqeMzyB52OiA9WFyc7su2fKeMrB+rI5YSNJRKsQONorVA60/SsUr3VGVgXVjbdPPapEiZvVJ6xXWgW3aTSZly87+BhvAauzyO9gEZmKwSr8PNpI1Tb8wjbsXbCR7afoVcd56hV3K+BwCBoPBYH/DntCZZzz1A5uaAAAAAElFTkSuQmCC"
}
...or run this script (again includes several ways to invoke the same action)
./10-maven-action-qr-gen-run.sh
Then go here and enjoy!