OpenFaaS is an open-source Function-As-A-Service (FaaS) project which works with Docker Swarm. FaaS provides the ability to run a function by itself or with other functions in a workflow to process information. A function running as a service will be able to scale up or down depending on how much it's used. OpenFaaS will manage Docker containers and function scaling.
This tutorial demonstrates how to deploy a Python 3 function on Docker Swarm and OpenFaaS. The Vultr firewall will prevent extra services being exposed and the Vultr private network will allow Docker nodes to communicate.
The Vultr firewall needs to allow incoming port 22 for SSH, and 8080 for OpenFaaS WebUI and functions. To deploy the firewall on Vultr:
Add a description for the firewall group. This tutorial will use openfaas_fw to to reference this group.
Add rules to the firewall by clicking the + sign under the Inbound IPv4 Rules section. Two rules will automatically be created: Accept traffic to SSH/port 22, and drop any other traffic.
Add a new rule: Accept TCP protocol on port 8080 for OpenFaaS. Check the Vultr Firewall FAQ to learn more.
Click the Deploy button.
Navigate to the Network tab in the customer portal. Click the Private Networks category. This page will provide the IP range for the private network. In this post, the 192.0.2.0/24 subnet will be used.
SSH into both ds1 and ds2 and use the Configuring Private Network guide to set the static IP addresses on interface ens7. Display the MAC address for the ens7 (private network) interface on both hosts.
# ip link show ens7
This MAC address will have to be used in the ens7 netplan configuration file. For this tutorial, ds1 (manager node) is assigned 192.0.2.1 and ds2 (worker node) is assigned 192.0.2.2. Replace these values with your private network information.
Disable the firewall on both of the hosts:
# ufw disable
Verify the private network is working by pinging from each host to the other host
Sets up Docker swarm and make ds1 a manager node. On ds1, execute:
# docker swarm init --advertise-addr 192.0.2.1
When the command is executed, it will display a swarm join command, similar to this:
To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-45m6nb1r1i2 ...
Paste that command in the ds2 terminal session to make ds2 a worker node.
root@ds2:~# docker swarm join --token SWMTKN-1-45m6nb1r1i2 ... This node joined a swarm as a worker.
On host ds1, verify that the worker node appears in the swarm list.
root@ds1:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zdwu416f6eua853dz873nqf2w * ds1 Ready Active Leader 19.03.9 pwyjws14064v1vs5c4pjzo39o ds2 Ready Active 19.03.9
On ds1, the manager node, install OpenFaaS:
root@ds1:~# git clone https://github.com/openfaas/faas root@ds1:~# cd faas root@ds1:~# ./deploy_stack.sh
Look for a [Credentials] section in the output. Make note of the username, password, and the shell command displayed.
On ds1, the manager node, install the OpenFaaS command-line utility. The command-line utility provides the ability to build and deploy functions.
root@ds1:~# curl -sSL https://cli.openfaas.com | sudo sh
On ds1, the manager node, execute the shell command provided under the [Credentials] section previously. Below is a truncated example. This authenticates OpenFaaS on the manager node.
root@ds1:~# echo -n c90d...468b | faas-cli login --username=admin --password-stdin
This is a Python 3 function that returns the current time and your name. On ds1, the manager node, execute the following commands to deploy a function named whattimeisit.
root@ds1:~# cd ~/ && mkdir functions && cd functions root@ds1:~/functions# faas-cli new whattimeisit --lang python3 root@ds1:~/functions# ls -l total 12 drwxr-xr-x 21 root root 4096 Jun 10 19:44 template drwx------ 2 root root 4096 Jun 10 19:44 whattimeisit -rw------- 1 root root 178 Jun 10 19:44 whattimeisit.yml
root@ds1:~/functions# nano whattimeisit/handler.py
Replace the contents with the following code:
#import datetime library so it can be used to determine the current time import datetime #req is the data provided as an input to the function def handle(req): #build a string to return retstring = "Hello %s, it's %s"%(req, datetime.datetime.now()) return retstring
Save and exit the file. Execute the following to build and deploy the function:
root@ds1:~/functions# faas-cli build -f ./whattimeisit.yml root@ds1:~/functions# faas-cli deploy -f ./whattimeisit.yml
Test the function, it should work from either node, to either node.
root@ds1:~# curl http://192.0.2.1:8080/function/whattimeisit -d "John" Hello John, it's 2020-01-01 01:01:01 root@ds1:~# curl http://192.0.2.2:8080/function/whattimeisit -d "John" Hello John, it's 2020-01-01 01:01:01
root@ds2:~# curl http://192.0.2.1:8080/function/whattimeisit -d "John" Hello John, it's 2020-01-01 01:01:01 root@ds2:~# curl http://192.0.2.2:8080/function/whattimeisit -d "John" Hello John, it's 2020-01-01 01:01:01