PolarSPARC

Getting Started with Serverless using OpenFaaS (ARM Edition)


Bhaskar S 02/22/2019


Overview

There has been quite a buzz around Serverless for a while now, which all started with the introduction of AWS Lambda, followed by Google Functions and Microsoft Azure Functions. So what is Serverless ???

Serverless is a software design pattern, in which, one builds and runs applications as individual and autonomous functions, without worrying about the infrastructure (hardware and software) administration and management.

In other words, application developers focus on building business applications, while the Serverless platform provider(s) focus on automatic provisioning, scaling, and managing of the backend infrastructure components (compute, database, network, storage, etc).

Serverless does not mean there is no server (compute, network, storage, software), but is fully outsourced, administered, and managed by the cloud provider, which is highly-resilient and fault-tolerant. This way the developers can focus primarily on the business applications, processes, and procedures for application upgrades.

Serverless is the combination of *BOTH* the business logic deployed as independent, autonomous functions often referred to as Function as a Service (FaaS for short) *AS WELL AS* the fully managed backend infrastructure components that is often referred to as Backend as a Service (BaaS for short).

OpenFaaS is an open-source framework for building and running Serverless functions either on-premise (using container orchestration platforms, such as, Docker Swarm, Kubernetes, etc) or in any of the cloud providers (AWS, Azure, GCE, etc), using Docker containers, without worrying about any kind of vendor lock-in.

Functions in OpenFaaS can be implemented in any of the popular languages, such as, C#, Go, Java, Node, Python, Ruby, etc.

In this article, we will demonstrate how to setup, deploy, and test OpenFaaS on-premise using Docker Swarm, running on a 5-node ARM cluster.

The following Figure-1 illustrates the high-level architectural overview of OpenFaaS running deployed on Docker Swarm cluster:

OpenFaaS
Figure-1

The core components of the OpenFaaS stack are as follows:

Installation and Setup

The installation will be on a 5-node ODroid XU4 Cluster running Linux.

For this tutorial, let us assume the 5-nodes in the cluster to have the following host names and ip addresses:

Host name IP Address
my-xu4-1 192.168.1.31
my-xu4-2 192.168.1.32
my-xu4-3 192.168.1.33
my-xu4-4 192.168.1.34
my-xu4-5 192.168.1.35

Open a Terminal window and open a tab for each of the 5 nodes my-xu4-1 thru my-xu4-5. In each of the Terminal tabs, ssh into the corresponding node.

First we need to install Docker on each of the nodes my-xu4-<N>, where <N> ranges from 1 thru 5. The current version as of this article is 18.06. Execute the following commands:

$ sudo apt-get update

$ sudo apt-get install -y docker.io

$ sudo usermod -aG docker $USER

$ sudo reboot now

Once reboot completes, open a Terminal window, open a tab for each of the 5 nodes my-xu4-1 thru my-xu4-5, and ssh into each of the nodes.

To verify Docker installation, execute the following command on the master node my-xu4-1:

$ docker info

The following would be a typical output:

Output.1

Containers: 5
 Running: 0
 Paused: 0
 Stopped: 5
Images: 19
Server Version: 18.06.1-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: active
 NodeID: knqpusrw3u3fcbi5dv8p4q4g9
 Is Manager: true
 ClusterID: uoo4ekrlqnyx0oer97y48ohrv
 Managers: 1
 Nodes: 5
 Orchestration:
  Task History Retention Limit: 5
 Raft:
  Snapshot Interval: 10000
  Number of Old Snapshots to Retain: 0
  Heartbeat Tick: 1
  Election Tick: 10
 Dispatcher:
  Heartbeat Period: 5 seconds
 CA Configuration:
  Expiry Duration: 3 months
  Force Rotate: 0
 Autolock Managers: false
 Root Rotation In Progress: false
 Node Address: 192.168.1.31
 Manager Addresses:
  192.168.1.31:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version:  (expected: 468a545b9edcd5932818eb9de8e72413e616e86e)
runc version: N/A (expected: 69663f0bd4b60df09991c08812a60108003fa340)
init version: v0.18.0 (expected: fec3683b971d9c3ef73f284f176672c44b448662)
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.14.94-odroidxu4
Operating System: Ubuntu 18.04.2 LTS
OSType: linux
Architecture: armv7l
CPUs: 8
Total Memory: 1.95GiB
Name: my-xu4-1
ID: ADJ5:ZABT:S7RF:UAZH:5U5R:F7F4:BE4U:TXIW:FCMZ:6TXN:ONLH:VG6L
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: bswamina
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

We will be using golang to write a simple Serverless functions using OpenFaaS. So, we need to install golang on each of the nodes my-xu4-<N>, where <N> ranges from 1 thru 5. The current version as of this article is 1.10.4. Execute the following command:

$ sudo apt install -y golang

To verify golang installation, execute the following command on the master node my-xu4-1:

$ go version

The following would be a typical output:

Output.2

go version go1.10.4 linux/arm

The node my-xu4-1 will be the master node in our Docker Swarm cluster.

On the master node my-xu4-1, execute the following command:

$ docker swarm init

The following would be a typical output:

Output.3

Swarm initialized: current node (abcd12345efgh67890ijklmo1) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-3l12aaabbb23bbbbbcccccc45dddd67eeeeeee89ffffffffff-0gggggg1hhhhhh2jjjjjjj3kk 192.168.1.31:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

On the master node my-xu4-1, execute the following command:

$ docker node ls

The following would be a typical output:

Output.4

ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
abcd12345efgh67890ijklmo1 *   my-xu4-1            Ready               Active              Leader              18.06.1-ce

On the worker nodes my-xu4-2 thru my-xu4-5, execute the following command:

$ docker swarm join --token SWMTKN-1-3l12aaabbb23bbbbbcccccc45dddd67eeeeeee89ffffffffff-0gggggg1hhhhhh2jjjjjjj3kk 192.168.1.31:2377

The following would be a typical output:

Output.5

This node joined a swarm as a worker.

On the master node my-xu4-1, execute the following command:

$ docker node ls

The following would be a typical output:

Output.6

ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
abcd12345efgh67890ijklmo1 *   my-xu4-1            Ready               Active              Leader              18.06.1-ce
n5rspb60lgux2g4cna2rr79gj     my-xu4-2            Ready               Active                                  18.06.1-ce
a73k8zolxxij3tajv7geje1o7     my-xu4-3            Ready               Active                                  18.06.1-ce
c09m70194x72ffb2j858gshe7     my-xu4-4            Ready               Active                                  18.06.1-ce
oz1jz0prf2r0wb2j5os7xbcbx     my-xu4-5            Ready               Active                                  18.06.1-ce

On the master node my-xu4-1, execute the following command:

$ docker service ls

The following would be a typical output:

Output.7

ID                  NAME                MODE                REPLICAS            IMAGE               PORTS

As can be inferred from Output.7 above, there are no services running yet.

Now we want to download and deploy OpenFaaS on our Docker Swarm cluster.

On the master node my-xu4-1, execute the following commands:

$ cd $HOME/Downloads

$ git clone https://github.com/alexellis/faas/

The following would be a typical output:

Output.8

Cloning into 'faas'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 18141 (delta 1), reused 3 (delta 1), pack-reused 18130
Receiving objects: 100% (18141/18141), 22.47 MiB | 11.13 MiB/s, done.
Resolving deltas: 100% (7590/7590), done.

To deploy the OpenFaaS stack in our Docker Swarm cluster, execute the following commands on the master node my-xu4-1:

$ cd $HOME/Downloads/faas

$ ./deploy_stack.sh

The following would be a typical output:

Output.9

Attempting to create credentials for gateway..
rf8sjlfez8r4erqf7op378e71
4x09nxubnam53ukxshzzkdna0
[Credentials]
 username: admin 
 password: 111111aaaaaa222222bbbbbb333333cccccc444444dddddd555555eeeeee6f7g
 echo -n 111111aaaaaa222222bbbbbb333333cccccc444444dddddd555555eeeeee6f7g | faas-cli login --username=admin --password-stdin

Enabling basic authentication for gateway..

Deploying OpenFaaS core services for ARM
Creating network func_functions
Creating config func_alertmanager_config
Creating config func_prometheus_config
Creating config func_prometheus_rules
Creating service func_faas-swarm
Creating service func_nats
Creating service func_queue-worker
Creating service func_prometheus
Creating service func_alertmanager
Creating service func_gateway

OpenFaaS expects basic-auth credentials in all communications with it.

From the Output.9 above, we see the default user is admin and the password 111111aaaaaa222222bbbbbb333333cccccc444444dddddd555555eeeeee6f7g.

On the master node my-xu4-1, execute the following command:

$ docker service ls

The following would be a typical output:

Output.10

ID                  NAME                MODE                REPLICAS            IMAGE                                 PORTS
1fi7v6wqu251        func_alertmanager   replicated          1/1                 functions/alertmanager:0.15.0-armhf   
bn718v0e17j6        func_faas-swarm     replicated          1/1                 openfaas/faas-swarm:0.6.1-armhf       
ta5l78be3sd7        func_gateway        replicated          1/1                 openfaas/gateway:0.11.0-armhf         *:8080->8080/tcp
s0rzg4g9frs3        func_nats           replicated          1/1                 nats-streaming:0.11.2                 
u3924uaou0dx        func_prometheus     replicated          1/1                 functions/prometheus:2.7.0-armhf      *:9090->9090/tcp
wud849pyaqym        func_queue-worker   replicated          1/1                 openfaas/queue-worker:0.6.0-armhf

As is evident from the Output.10 above, we have successfully deployed the components of OpenFaaS stack in our Docker Swarm cluster.

One important point to note from the Output.10 above - we have an API gateway running at the endpoint http://192.168.1.31:8080.

Open a browser and enter the API gateway URL running at http://192.168.1.31:8080.

The following Figure-2 illustrates the view of the API gateway in the browser:

API Gateway
Figure-2

In order to manage the lifecycle (create, build, deploy, delete) of Serverless functions in OpenFaaS, we need to install a CLI utility called faas-cli. To do that, execute the following command on the master node my-xu4-1:

$ curl -sSL cli.openfaas.com | sudo sh

The following would be a typical output:

Output.11

armv7l
Downloading package https://github.com/openfaas/faas-cli/releases/download/0.8.3/faas-cli-armhf as /tmp/faas-cli-armhf
Download complete.

Running as root - Attempting to move faas-cli to /usr/local/bin
New version of faas-cli installed to /usr/local/bin
Creating alias 'faas' for 'faas-cli'.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|

CLI:
 commit:  a141dedf94ffeed84412365fd591bdc8999c5a1b
 version: 0.8.3

To verify if the CLI utility faas-cli has been installed properly, execute the following command on the master node my-xu4-1:

$ faas-cli

The following would be a typical output:

Output.12

  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Manage your OpenFaaS functions from the command line

Usage:
  faas-cli [flags]
  faas-cli [command]

Available Commands:
  build          Builds OpenFaaS function containers
  cloud          OpenFaaS Cloud commands
  deploy         Deploy OpenFaaS functions
  describe       Describe an OpenFaaS function
  generate       Generate Kubernetes CRD YAML file
  help           Help about any command
  invoke         Invoke an OpenFaaS function
  list           List OpenFaaS functions
  login          Log in to OpenFaaS gateway
  logout         Log out from OpenFaaS gateway
  new            Create a new template in the current folder with the name given as name
  push           Push OpenFaaS functions to remote registry (Docker Hub)
  remove         Remove deployed OpenFaaS functions
  secret         OpenFaaS secret commands
  store          OpenFaaS store commands
  template       OpenFaaS template store and pull commands
  up             Builds, pushes and deploys OpenFaaS function containers
  version        Display the clients version information

Flags:
      --filter string   Wildcard to match with function names in YAML file
  -h, --help            help for faas-cli
      --regex string    Regex to match with function names in YAML file
  -f, --yaml string     Path to YAML file describing function(s)

Use "faas-cli [command] --help" for more information about a command.

Thats it !!! This completes the installation and setup process.

Hands-on with OpenFaaS

We want to quickly demonstrate a Serverless function using golang running on OpenFaaS.

First we need to setup a structure for our golang project. To do that, execute the following commands on my-xu4-1:

$ mkdir -p $HOME/Projects/go

$ export GOPATH=$HOME/Projects/go

$ cd $GOPATH

$ mkdir -p src/functions

$ cd src/functions

To create a new Serverless function, with the API gateway running at http://192.168.1.31:8080, execute the following commands on the master node my-xu4-1:

$ mkdir goecho

$ cd goecho

$ faas-cli new --lang go-armhf goecho --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.13

2019/02/18 15:15:48 No templates found in current directory.
2019/02/18 15:15:48 Attempting to expand templates from https://github.com/openfaas/templates.git
2019/02/18 15:15:48 Fetched 15 template(s) : [csharp csharp-armhf dockerfile go go-armhf java8 node node-arm64 node-armhf php7 python python-armhf python3 python3-armhf ruby] from https://github.com/openfaas/templates.git
Folder: goecho created.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Function created in folder: goecho
Stack file written: goecho.yml

ATTENTION: ARM Users

Ensure the value for the option --lang is *go-armhf*. Else later will encounter the following error:

standard_init_linux.go:190: exec user process caused "exec format error"

On the master node my-xu4-1, execute the following command:

$ ls -l

The following would be a typical output:

Output.14

total 12
drwx------  2 xu4 xu4 4096 Feb 18 13:54 goecho
-rw-------  1 xu4 xu4  137 Feb 18 13:54 goecho.yml
drwxrwxr-x 17 xu4 xu4 4096 Feb 18 13:54 template

The OpenFaaS function creation process creates a sub-directory by the name goecho which will contain the function wrapper file called handler.go as shown below:

goecho/handler.go
package function

import (
  "fmt"
)

// Handle a serverless request
func Handle(req []byte) string {
  return fmt.Sprintf("Hello, Go. You said: %s", string(req))
}

It is the above function wrapper that gets executed when the Serverless function is invoked.

Since we will be running the OpenFaaS build process to package our simple Serverless function as a Docker image locally on the master node my-xu4-1, we need to push the Docker image to either a private Docker registry or the public Docker hub. This way the Docker image will be accessible to the other nodes in the Docker Swarm cluster.

For this exercise, will be pushing the Docker image to my registered public Docker hub repository. Ensure you have registered and created your own repository at Docker Hub site.

In order to push the Docker image to a registered public Docker hub repository, modify the line image: in the file goecho.yml to point to your repository in the format: user-id/image-name:latest (bswamina/goecho:latest for my case), as shown below:

goecho.yml
provider:
  name: faas
  gateway: http://192.168.1.31:8080
functions:
  goecho:
    lang: go
    handler: ./goecho
    image: bswamina/goecho:latest

To build the newly created Serverless function, execute the following command on the master node my-xu4-1:

$ faas-cli build -f goecho.yml

The following would be a typical output:

Output.15

[0] > Building goecho.
Clearing temporary build folder: ./build/goecho/
Preparing ./goecho/ ./build/goecho/function
Building: bswamina/goecho:latest with go-armhf template. Please wait..
Sending build context to Docker daemon  6.656kB
Step 1/18 : FROM golang:1.10.4-alpine3.8 as builder
1.10.4-alpine3.8: Pulling from library/golang
905674ea9d94: Already exists 
d91fe322e169: Already exists 
539e55f19a97: Pull complete 
709c5449f2ce: Pull complete 
bc40f6a203c9: Pull complete 
b311e7c16063: Pull complete 
Digest: sha256:55ff778715a4f37ef0f2f7568752c696906f55602be0e052cbe147becb65dca3
Status: Downloaded newer image for golang:1.10.4-alpine3.8
 ---> e9cd6992c34f
Step 2/18 : RUN apk --no-cache add curl     && echo "Pulling watchdog binary from Github."     && curl -sSL https://github.com/openfaas/faas/releases/download/0.9.14/fwatchdog-armhf > /usr/bin/fwatchdog     && chmod +x /usr/bin/fwatchdog     && apk del curl --no-cache
 ---> Running in 5a94c235b4b2
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/armhf/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/armhf/APKINDEX.tar.gz
(1/4) Installing nghttp2-libs (1.32.0-r0)
(2/4) Installing libssh2 (1.8.0-r3)
(3/4) Installing libcurl (7.61.1-r1)
(4/4) Installing curl (7.61.1-r1)
Executing busybox-1.28.4-r1.trigger
OK: 5 MiB in 18 packages
Pulling watchdog binary from Github.
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/armhf/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/armhf/APKINDEX.tar.gz
(1/4) Purging curl (7.61.1-r1)
(2/4) Purging libcurl (7.61.1-r1)
(3/4) Purging nghttp2-libs (1.32.0-r0)
(4/4) Purging libssh2 (1.8.0-r3)
Executing busybox-1.28.4-r1.trigger
OK: 4 MiB in 14 packages
Removing intermediate container 5a94c235b4b2
 ---> a5f3507a4acc
Step 3/18 : WORKDIR /go/src/handler
 ---> Running in 7a824ec36182
Removing intermediate container 7a824ec36182
 ---> 174da2669536
Step 4/18 : COPY . .
 ---> fcf1c1e290c1
Step 5/18 : RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./function/vendor/*"))" || { echo "Run \"gofmt -s -w\" on your Golang code"; exit 1; }
 ---> Running in e8181f03983d
Removing intermediate container e8181f03983d
 ---> 1018979bc626
Step 6/18 : RUN CGO_ENABLED=0 GOOS=linux     go build --ldflags "-s -w" -a -installsuffix cgo -o handler . &&     go test ./... -cover
 ---> Running in 7f71e2530cb5
?     handler [no test files]
?     handler/function  [no test files]
Removing intermediate container 7f71e2530cb5
 ---> 1eb4a39a95de
Step 7/18 : FROM alpine:3.8
3.8: Pulling from library/alpine
5b678b67777f: Pull complete 
d9f0b2b885d9: Pull complete 
Digest: sha256:dad671370a148e9d9573e3e10a9f8cc26ce937bea78f3da80b570c2442364406
Status: Downloaded newer image for alpine:3.8
 ---> d2696274f894
Step 8/18 : RUN apk --no-cache add ca-certificates
 ---> Running in e0b8d5e08e28
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/armhf/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/armhf/APKINDEX.tar.gz
(1/1) Installing ca-certificates (20171114-r3)
Executing busybox-1.28.4-r2.trigger
Executing ca-certificates-20171114-r3.trigger
OK: 4 MiB in 14 packages
Removing intermediate container e0b8d5e08e28
 ---> e74f07dd1e11
Step 9/18 : RUN addgroup -S app && adduser -S -g app app
 ---> Running in d2339abaa87f
Removing intermediate container d2339abaa87f
 ---> 51abcebb1738
Step 10/18 : RUN mkdir -p /home/app
 ---> Running in f235f97e381e
Removing intermediate container f235f97e381e
 ---> 4623d0af0926
Step 11/18 : RUN chown app /home/app
 ---> Running in f8adab6db4c2
Removing intermediate container f8adab6db4c2
 ---> 24c51ba52440
Step 12/18 : WORKDIR /home/app
 ---> Running in 586d354913de
Removing intermediate container 586d354913de
 ---> 59b1ced9399f
Step 13/18 : COPY --from=builder /go/src/handler/handler    .
 ---> 45e369824609
Step 14/18 : COPY --from=builder /usr/bin/fwatchdog         .
 ---> 4688e2f1e6f4
Step 15/18 : USER app
 ---> Running in 8471863762a4
Removing intermediate container 8471863762a4
 ---> 577e2ea75659
Step 16/18 : ENV fprocess="./handler"
 ---> Running in e249eb4c0d06
Removing intermediate container e249eb4c0d06
 ---> 6654ca56a089
Step 17/18 : EXPOSE 8080
 ---> Running in 25e522029405
Removing intermediate container 25e522029405
 ---> 2bccc4e3964f
Step 18/18 : CMD ["./fwatchdog"]
 ---> Running in 1dbba351c064
Removing intermediate container 1dbba351c064
 ---> 864958423067
Successfully built 864958423067
Successfully tagged bswamina/goecho:latest
Image: bswamina/goecho:latest built.
[0] < Building goecho done.
[0] worker done.

To push the locally build Docker image to the registered public Docker hub repository, execute the following command on the master node my-xu4-1:

$ faas-cli push -f goecho.yml

The following would be a typical output:

Output.16

The push refers to repository [docker.io/bswamina/goecho]
b044b70d3985: Preparing 
f9f02de17ab9: Preparing 
1795e4fc8c3d: Preparing 
0b82126cfc0d: Preparing 
153b2ef38418: Preparing 
169699648f59: Waiting 
4d6f2b7ff2f4: Waiting 
e093aa48fce2: Waiting 
denied: requested access to the resource is denied
2019/02/18 14:14:14 ERROR - Could not execute command: [docker push bswamina/goecho:latest]

OOPS !!! What happened here ???

In order to push a Docker image to the registered public Docker hub repository, we need to first login with our registered credentials.

To login to our registered public Docker hub repository, execute the following command on the master node my-xu4-1:

$ docker login

We will be prompted for our user-id and password. Once we enter those, the following would be a typical output:

Output.17

Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: bswamina
Password: 
WARNING! Your password will be stored unencrypted in /home/xu4/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Now, retry to push the just built Docker image by executing the following command on the master node my-xu4-1:

$ faas-cli push -f goecho.yml

The following would be a typical output:

Output.18

[0] > Pushing goecho [bswamina/goecho:latest].
The push refers to repository [docker.io/bswamina/goecho]
d376bd085999: Pushed 
15e64d94e801: Pushed 
dea44b3f24ed: Pushed 
93012c148c7b: Pushed 
a58ab9e53859: Pushed 
4d6f2b7ff2f4: Mounted from library/alpine 
e093aa48fce2: Mounted from library/alpine 
latest: digest: sha256:af0afb00ba26881c665ca0160d79f846f66d0a7ca4c2f1e11a1facbed913b3f6 size: 1781
[0] < Pushing goecho [bswamina/goecho:latest] done.
[0] worker done.

BINGO !!! success this time.

Now comes the interesting part. To deploy our Serverless function packaged in a Docker image called bswamina/goecho:latest (with the API gateway running at http://192.168.1.31:8080), execute the following command on the master node my-xu4-1:

$ faas-cli deploy -f goecho.yml --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.19

Deploying: goecho.

unauthorized access, run "faas-cli login" to setup authentication for this server

WHAT ???

Remember OpenFaaS uses basic-auth protection. Hence, we first need to authenticate with the API gateway http://192.168.1.31:8080 using the basic-auth credentials.

To authenticate with the API gateway at http://192.168.1.31:8080, execute the following command on the master node my-xu4-1:

$ echo -n 111111aaaaaa222222bbbbbb333333cccccc444444dddddd555555eeeeee6f7g | faas-cli login --username=admin --password-stdin --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.20

Calling the OpenFaaS server to validate the credentials...
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
credentials saved for admin http://192.168.1.31:8080

Now, we will re-try the command to deploy our Serverless function by executing the following command on the master node my-xu4-1:

$ faas-cli deploy -f goecho.yml --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.21

Deploying: goecho.

Deployed. 202 Accepted.
URL: http://192.168.1.31:8080/function/goecho

To verify deployment of our Serverless function, execute the following command on the master node my-xu4-1:

$ docker service ls

The following would be a typical output:

Output.22

ID                  NAME                MODE                REPLICAS            IMAGE                                 PORTS
1fi7v6wqu251        func_alertmanager   replicated          1/1                 functions/alertmanager:0.15.0-armhf   
bn718v0e17j6        func_faas-swarm     replicated          1/1                 openfaas/faas-swarm:0.6.1-armhf       
ta5l78be3sd7        func_gateway        replicated          1/1                 openfaas/gateway:0.11.0-armhf         *:8080->8080/tcp
s0rzg4g9frs3        func_nats           replicated          1/1                 nats-streaming:0.11.2                 
u3924uaou0dx        func_prometheus     replicated          1/1                 functions/prometheus:2.7.0-armhf      *:9090->9090/tcp
wud849pyaqym        func_queue-worker   replicated          1/1                 openfaas/queue-worker:0.6.0-armhf     
1nkewwozf2g0        goecho              replicated          1/1                 bswamina/goecho:latest

BINGO !!! As is evident from the Output.22 above, we see that we have successfully deployed our first Serverless function to our Docker Swarm cluster.

Now comes the *FUN* part. To test our deployed Serverless function called goecho (with the API gateway running at http://192.168.1.31:8080), execute the following command on the master node my-xu4-1:

$ echo "Howdy" | faas-cli invoke goecho --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.23

Hello, Go. You said: Howdy

YIPEE !!! As is evident from the Output.23 above, we have a successful response from our first Serverless function.

One can also invoke the deployed Serverless function via a web-browser through the API gateway URL located at http://192.168.1.31:8080.

The following Figure-3 illustrates the view of the Serverless function invocation via the API gateway in the browser:

Invoke Function
Figure-3

To delete our deployed Serverless function called goecho (with the API gateway running at http://192.168.1.31:8080), execute the following command on the master node my-xu4-1:

$ faas-cli remove goecho --gateway http://192.168.1.31:8080

The following would be a typical output:

Output.24

Deleting: goecho.
Removing old function.

With this, we conclude the basic exercises we performed on our Docker Swarm cluster running OpenFaaS.

References

Official OpenFaaS Documentation



© PolarSPARC