Al’s Simple Oracle Functions Setup
Going Serverless
Oracle Functions provides a way to build serverless applications in a similar way to AWS Lambda, but at lower cost and uses open source software from fnproject. This article describes how to setup your laptop to use Oracle Functions in the cloud to develop serverless applications.
When you write your serverless code, you can program in any language you like, Java, Node.js, Go, Ruby, Python — anything that will run in a docker container including C#.
The setup seems quite long and can be off putting, but it is a pretty much a one time activity and once done, I’ll show how you can run a function using just four commands:
fn init --runtime node nodefn
cd nodefn
fn deploy -app alsfn1
fn invoke alsfn1 nodefn
Returning:
{“message”:”Hello World”}
That’s how easy it is.
Suggested Prerequisites
The steps assume you already have an Oracle OCI Tenancy, but if not, you can start with a ‘free tier’ tenancy from here: oracle.com. If struggling to create your free tier tenancy for whatever reason then contact Oracle Support.
When you’ve written your code, you will then ‘deploy’, which will automatically package your code into a docker image, push this docker image to a docker registry; and later when you invoke your code, it will automatically pull this docker image and run it for you.
By default this image will be stored on your laptop. There are many benefits to using a registry service instead, and Oracle provide one called the Oracle Cloud Infrastructure Registry (OCIR). If you want to use OCIR and you haven’t already set it up, it is recommended that this is done before continuing, by following the steps in this article: medium.com/@virtorg
We’ll start on the Oracle Cloud Infrastructure (OCI) console.
Get Your Compartment
Most of the development time spent writing serverless functions will happen on your laptop. But you also need to setup a few things on Oracle Cloud Infrastructure (OCI) to deploy and run your functions.
First we collect some information we’ll use later to setup our laptop. We need the Oracle Cloud Identifier, or ‘OCID’ of the Compartment in which we will build our cloud assets.
In a nutshell a Compartment is a way in which we can logically group our cloud assets and in our case it is where we will create our network and functions. Out of the box, OCI comes with a ‘root’ Compartment, but you shouldn’t put any assets in there. Instead you should create one. If you’re not sure what a Compartment is please see: docs.cloud.oracle.com and for instructions on creating a Compartment: docs.cloud.oracle.com. Going forwards, I assume you already have one created.
To get the OCID for your Compartment, login to your OCI tenancy at cloud.oracle.com and from the OCI console click on the menu on the top left of the screen, select: Identity> Compartments:

Scroll down to your Compartment and click on the OCID:

Select ‘copy’ to copy the OCID and paste it onto your laptop in a program like TextEdit or Notepad because we will need it later.
Setup Your Network
When we deploy our serverless function onto OCI, it needs access to a cloud network on OCI, known as a Virtual Cloud Network or VCN. If you don’t already have one already created, we need to create a VCN, with a subnet first, before we can deploy our function. This is simple with the OCI VCN Wizard.
Again from the OCI console click on the menu on the top left of the screen, select: Networking > Virtual Cloud Networks:

Ensure you are in your Compartment and select ‘Start VCN Wizard’ :

Select ‘VCN with Internet Connectivity’ and Click on ‘Start VCN Wizard’:

Complete the wizard with the values you want. I just gave it a name: ‘AlsFnVCN’ and took the default values for the subnets below:

Click ‘Next’ and then on the next page click ‘Create’.
Create Permissions
Next we need to create some policies to allow our functions to access this VCN and to also allow our functions to access our registry. This is assuming we are using the Oracle registry or OCIR as mentioned earlier. From the OCI console click on the menu on the top left of the screen, select: Identity> Policies:

This time, ensure you are in the ‘root’ compartment for your tenancy:

Click on ‘Create Policy’:

And give the policy a name and description:

Add the policy statements:
- allow service FAAS to use virtual-network-family in tenancy
- allow service FAAS to read repos in tenancy
And Click ‘Create’.
So now we have a network created, given our Oracle Functions service permission to access that network and given the Oracle Functions service permission to access our OCI registry.
Setting Up Function Logging
When you are developing your function, you will probably deploy it numerous times during testing. Although not essential for Oracle Functions to work, I would suggest it is crucial that you have logging setup so that you can see what’s happening as you debug your function.
There are a couple of ways you could do this today:
- Logging To Object Storage
- SYSLOGURL
If you decide on ‘Object Storage’ it creates a bucket and outputs the logs there:

If you click the bucket, you can see the logs that have been written:

You can download these ‘gz’ files and unzip them and this is what they look like:
{“ts”:1589796652062,”aid”:”ocid1.fnapp.oc1.phx.aaaaaaabcd342424f34f3fa313a33453453kjh54j34h5j5h3j5hjh5j53kj4jh5j45h3jh54”,”cid”:”09754857959229",”fid”:”ocid1.fnfunc.oc1.phx.aaaaaaabcd342424f34f3fa313a33453453kjh54j34h5j5h3j5hjh5j53kj4jh5j45h3jh54”,”rid”:”/865439458359384535845385”,”src”:”STDERR”,”msg”:”(node:7) UnhandledPromiseRejectionWarning: TypeError: Cannot read property ‘then’ of undefined”{“ts”:1589796652062,”aid”:”ocid1.fnapp.oc1.phx.aaaaaaabcd342424f34f3fa313a33453453kjh54j34h5j5h3j5hjh5j53kj4jh5j45h3jh54”,”cid”:”09754857959229",”fid”:”ocid1.fnfunc.oc1.phx.aaaaaaabcd342424f34f3fa313a33453453kjh54j34h5j5h3j5hjh5j53kj4jh5j45h3jh54”,”rid”:”/865439458359384535845385”,”src”:”STDERR”,”msg”:” at sendResult (/function/node_modules/@fnproject/fdk/fn-fdk.js:153:5)”}………………
The drawback with the Log To Object Storage is that it flushes the logs to Object Storage every few minutes, even up to 20 mins, so it can take a while to get your logs after your function has finished executing. Plus there is no additional tooling to interrogate the logs. So I use SYSLOGURL because then the logs are available almost immediately and you get a lot more functionality.
SYSLOGURL requires a third party logging service, but don’t let that put you off because it is quick and easy to setup. Papertrail is one I use and you can setup a free account (for non production use). Just sign into Papertrail by going to papertrail.com:

Click ‘Start Logging’, which will prompt you to create an account and once done, go to settings — Log Destinations:

This takes you here:

Make a note of the URL, in my case: log.papertrail.com:87654
. We’ll need that later to configure Oracle Functions. Click on settings:

At the bottom of the screen, deselect the ‘TLS’ checkbox and Select ‘Plain Text’, then click Update to complete the setup.
Later when we deploy our function, we can view our logs by selecting from ‘Events’ from the Papertrail dashboard:

As an example, a node function that I created had this line:
console.log(‘\nInside Node Hello World function’)
And this should send this output to Papertrail to be seen in the log within a few seconds.
Just to mention there is a native OCI Cloud Logging Service which will be available soon and I’ll update this article with the details once it is generally available.
Create An Application
Next create our Oracle Functions ‘Application’.
An ‘Application’ will consist of one or more Functions. We need to create an application before we create our first function. From the OCI console click on the menu on the top left of the screen, select: Developer Services > Functions:

Make sure you’re in your compartment (not the ‘root’) and select ‘Create Application’:

This takes you here:

Give your application a name, eg alsfn1, select the VCN we created earlier and the subnet(s) which the function will be networked. Notice the logging options we discussed earlier and I’ve selected: SYSLOGURL. I use the URL from Papertrail, with tcp://
prepended thus:
tcp://log.papertrail.com:87654
You would or course use your own logging URL here instead.
Finally click ‘Create’.

On The Laptop
So we now have everything setup on OCI and can begin to setup functions or fn on our laptop.
As I mentioned earlier, when we create a function, it creates a docker image and we will push this image to a registry like dockerhub or better still to the Oracle Cloud Infrastructure Registry (OCIR). The reason it is better to push it to OCIR is because it is then close to the compute used by Oracle Functions and can be pulled down over the network to the compute and executed more quickly.
In order to push Docker images up to the OCIR registry from your laptop, we need to be able to login to OCIR using the Docker command line interface (CLI) like this:
docker login phx.ocir.io -u yourtenancyname/oracleidentitycloudservice/joe.bloggs@yourdomain.com -p 3j34hj343jh323j
…but using your credentials of course. If you don’t know where these parameters come from, then you probably haven’t setup the Oracle Cloud Infrastructure Registry (OCIR), but that’s fine as it’s all explained here: medium.com/@virtorg
So once you’re setup to use OCIR, open a terminal and type:docker login
with your credentials to login to OCIR. It caches your credentials locally, which is a bit of a security risk, which is why it is recommended you consider using an external credentials store (see: docs.docker.com).
After logging into OCIR, install the fn CLI from fnproject on your laptop. Installation is explained at fnproject and to do this on a Mac, simply open a terminal and type:
brew update && brew install fn
(If you don’t have brew on your Mac, install it by following: brew.sh)
This automatically places the command ‘fn’ in the directory:
/usr/local/bin/fn
To check it’s installed correctly type:
fn version
For me this returned:
Client version: 0.5.96 is not latest: 0.5.97
Server version: ?
We next need to setup a configuration file which fn will use to connect and authenticate on your OCI tenancy like this:
cat ~/.oci/config[DEFAULT]
user=ocid1.user.oc1..aaaaaaaazsd438958fjghjhj3h2j3h2j3h2
fingerprint=54:76:23:54:54:dd:23:f4:ef:3e:43:55:23:b3:5c:fa
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaat7gdsdf9s8fdafd98fd
region=us-phoenix-1
The easiest way to ensure you get all the correct values in this file, is to setup the OCI command line interface (CLI). This is described here: medium.com@virtorg
You don’t need to install the OCI CLI, you could just create the file ~/.oci/config
yourself and manually add the entries. But the OCI CLI often comes in useful, so worth the effort. The important outcome of setting up the OCI CLI is that it creates this configuration file with the correct credentials to match your tenancy, which fn can then use to push your functions to OCI.
fn Contexts
I’ve already mentioned that when you create your function, you create a docker image which is stored in a docker registry. By default, fn allows you to store your images locally on your laptop. But you could specify that you want to store the docker images in dockerhub or OCIR. You also need to specify where you are going to run your function, ie where is the function server going to be. To set this up so that your laptop knows where to find these things, we amend the fn context. After you’ve installed fn, you can determine your context by typing:
fn list contexts
Which returns:
CURRENT NAME PROVIDER API URL REGISTRY
* default default http://localhost:8080
After fn is installed, this configuration information is created on your laptop:
tree ~/.fn
.fn
├── config.yaml
├── contexts
│ └── default.yaml
├── data
│ ├── fn.db
│ └── fn.mq
└── iofs
Notice the subdirectory named ‘contexts’. In here is a file called ‘default.yaml’ and if you look inside there, this is where the ‘fn list contexts’ command got its information:
cat ~/.fn/contexts/default.yamlapi-url: http://localhost:8080
provider: default
registry: “”
Currently this doesn’t have a docker registry set, so will just use your laptop, ie the same place where you see your images via docker images
. For the function server, it is using http://localhost:8080
as the place where it will deploy your function, ie this is where it expects the function server to be running, which at the moment it expects to be on your laptop on port 8080.
So let’s say we want to use OCIR instead and we want to use our Oracle OCI Function Cloud Service as the place where we will run our serverless function, you would create a context so we can do this. To begin, type:
fn create context alsoraclecontext --provider oracle
This creates a file in ‘contexts’ called:
cat ~/.fn/contexts/alsoraclecontext.yamlapi-url: “”
provider: oracle
registry: “”
Now we can switch to use this context instead via:
fn use context alsoraclecontext
Then if we type:
fn list contextsCURRENT NAME PROVIDER API URL REGISTRY
* alsoraclecontext oracle
default default http://localhost:8080
You can see that I now have another context and the asterisk against it means this is the current one I’m using in my environment, but nothing much else.
I need to add more configuration information so I can actually use my Oracle registry and use my Oracle Functions. First we’ll tell it to use my compartment, AlanH
on tenancy yourtenancyname.
I need to find the Compartment OCID for AlanH
that I noted down earlier and use that:
fn update context oracle.compartment-id ocid1.compartment.oc1..aaa4342g2f1g234gf1g3f4g3f4gfgf41j5hgkg3h314h3g4
Next we’ll tell it the registry to use in the format:
fn update context registry <region-key>.ocir.io/<tenancy-namespace>/<repo-name>
thus:
fn update context registry phx.ocir.io/yourtenancyname/yourreponame
The next thing we need to do is provide the credentials that will be used to access the Oracle Functions cloud service. Now under the covers, the fn program uses the file already created: ~/.oci/config
[DEFAULT]
user=ocid1.user.oc1..aaaaaaaazsd438958fjghjhj3h2j3h2j3h2
fingerprint=54:76:23:54:54:dd:23:f4:ef:3e:43:55:23:b3:5c:fa
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaat7gdsdf9s8fdafd98fd
region=us-phoenix-1
So notice in the file, it shows the tenancy, region and importantly the login credentials. Notice it is listed under ‘DEFAULT’, which is known as the default profile.
If you didn’t want to use this default profile, you could add a profile to this ‘config’ file:
cat ~/.oci/config[DEFAULT]
user=ocid1.user.oc1..aaaaaaaazsd438958fjghjhj3h2j3h2j3h2
fingerprint=54:76:23:54:54:dd:23:f4:ef:3e:43:55:23:b3:5c:fa
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaat7gdsdf9s8fdafd98fd
region=us-phoenix-1[alstokyo]
user=ocid1.user.oc1..aaaaaaaazsd438958fjg5353559593599394
fingerprint=54:76:23:54:54:dd:23:f4:ef:3e:43:55:23:b3:5c:fa
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..aaaaaaaaaaffdrerereeer
region=ap-tokyo-1
And then to use this new information instead of the ‘DEFAULT, you would:
fn update context oracle.profile alstokyo
We used our DEFAULT profile, so now our context looks like this:
fn list contextsCURRENT NAME PROVIDER API URL REGISTRY
* alsoraclecontext oracle https://functions.us-phoenix-1.oci.oraclecloud.com phx.ocir.io/yourtenancyname/yourreponame default default http://localhost:8080
To check the configuration has worked:
fn list apps
which for me returned:
NAME ID
alsfn1 ocid1.fnapp.oc1.phx.aabbb89b8b9b9b8983949384989898gdfkggkdgj
Running A Serverless Application
Everything we’ve had to do above might seem a lot, but it is pretty much a one time setup. From now on, most of your time is spent developing functions.
Now we finally get to build and deploy our serverless function. I’ll show this using Node.js using just four commands. From your laptop, open a terminal and type:
fn init --runtime node nodefn
cd nodefn
fn -v deploy -app alsfn1
fn invoke alsfn1 nodefn
Which returns:
{“message”:”Hello World”}
That’s how easy it is. The code above created a simple Node.js project in the directory ./nodefn
You then run the command to deploy the function, which automatically creates the docker image with your code, with the node runtime and pushes it to OCIR and makes it available to run on Oracle Functions.
Then you invoke it, which causes Oracle Functions to run your code and return the result. Oracle Functions will provision enough compute to scale the Function automatically.
For more information about this code, please see: fnproject.io