Open-Faas on Centos 7

Heshani Samarasekara
Geek Culture
Published in
6 min readMay 7, 2022

Hello, In this article I will be going through steps for installing OpenFaas on centos 7 machine using minikube cluster and then deploying and running a go-microservice on top of this setup.

For this setup, I have been following OpenFaas workshop documents, and OpenFaas blog.

Prerequisites

  1. Docker : Instructions can be found from official Docker documentations.
  2. OpenFaas CLI : From official github documents.
    $ curl -sLSf https://cli.openfaas.com | sudo sh
  3. Minikube : I have followed steps from this document.
  4. A docker registry: In this case I have used my Harbor image registry, but you can follow my previous article to create your own docker registry. (Can use minikube Docker registry: eval $(minikube docker-env))
  5. Helm: Official installation guide.
  6. GO

Installation

As we have now collected our prerequisites, let’s move on to deploying OpenFaas.

First let’s start minikube.

minikube start

I have used helm charts for OpenFaas installation.

helm repo add openfaas https://openfaas.github.io/faas-netes/kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.ymlhelm repo update \
&& helm upgrade openfaas --install openfaas/openfaas \
--namespace openfaas \
--set functionNamespace=openfaas-fn \
--set generateBasicAuth=true

This will create two namespaces in the kubernetes cluster with names openfaas and openfaas-fn. We can check if our installation is success by checking the pod status as below.

kubectl get pods -n openfaas -w

All the pods should be in Running status.

We can check if the gateway is ready by below command.

kubectl rollout status -n openfaas deploy/gateway

Now we will get our authentication details from cluster. Below command will print the admin password for the openfaas login.

PASSWORD=$(kubectl -n openfaas get secret basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode) && \
echo "OpenFaaS admin password: $PASSWORD"

Then we need to port forward this port, to access from our machine.

export OPENFAAS_URL=http://127.0.0.1:31112
kubectl port-forward -n openfaas svc/gateway 31112:8080 &

For adding Prometheus(metrics), we can run below command.

kubectl --namespace openfaas port-forward deployment/prometheus 31119:9090

For adding grafana monitoring, let’s run below commands.

kubectl -n openfaas run \
--image=stefanprodan/faas-grafana:4.6.3 \
--port=3000 \
grafana
kubectl -n openfaas expose pod grafana \
--type=NodePort \
--name=grafana
GRAFANA_PORT=$(kubectl -n openfaas get svc grafana -o jsonpath="{.spec.ports[0].nodePort}")
GRAFANA_URL=http://127.0.0.1:$GRAFANA_PORT/dashboard/db/openfaas
kubectl port-forward pod/grafana 3000:3000 -n openfaas

Now we can access to the url http://127.0.0.1:31112 for openfaas ui(admin/generated password), http://127.0.0.1:31119 for Prometheus ui and http://127.0.0.1:3000 for Grafana ui(admin/admin).

To test things out, we can go to the openfaas ui and click on deploy new function. In the list choose ‘figlet’. After it is added to the left pane, add any text to the Request Body space and hit invoke button.

Pretty cool right!

Deploy Go-microservice

As we have now completed our installation, lets deploy a simple go-microservice in OpenFaas.

OpenFaas has several templates that we can use for our tasks. They maintain the templates in their template store.

faas-cli template pull

We can check the available templates with below command.

faas-cli template store pull

Then we can pull any template that we need as below. This will pull the templates for golang-http. We can use these templates and change them accordingly to meet our needs.

faas-cli template store pull golang-http

Or else, we can create our own function as described in next section.

First we have to create our function yaml file with Dockerfile.

faas-cli new --lang dockerfile go-microservice

You will get a go-microservice.yaml file, and go-microservice directory. In the yaml file, you can change the content as you wish. My yml file is as below. I have added my gateway and image urls accordingly.

version: 1.0
provider:
name: openfaas
gateway: http://127.0.0.1:31112
functions:
go-microservice:
lang: dockerfile
handler: ./go-microservice
image: localhost:5000/go-microservice:1.0

We can add any content for the generated Dockerfile, to be used in our function. I have used below content which is taken from here.

FROM golang:1.10.4-alpine3.8 as build

RUN mkdir -p /go/src/handler
WORKDIR /go/src/handler
COPY . .

RUN CGO_ENABLED=0 GOOS=linux \
go build --ldflags "-s -w" -a -installsuffix cgo -o handler . && \
go test $(go list ./... | grep -v /vendor/) -cover

FROM alpine:3.9
# Add non root user and certs
RUN apk --no-cache add ca-certificates \
&& addgroup -S app && adduser -S -g app app \
&& mkdir -p /home/app \
&& chown app /home/app

WORKDIR /home/app

COPY --from=build /go/src/handler/handler .

RUN chown -R app /home/app

RUN touch /tmp/.lock # Write a health check for OpenFaaS here or in the HTTP server start-up

USER app

CMD ["/home/app/handler"]

Then we have to add our middleware for this. In the go-microservice directory, add the main.go class.

package main

import (
"fmt"
"log"
"net/http"
"time"
)

func addServedHeader(w http.ResponseWriter, r *http.Request) {
w.Header().Add("X-Served-Date", time.Now().String())
}

func makeRequestHandler(middleware http.HandlerFunc) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
middleware(w, r)

w.Write([]byte("OK"))
}
}

func main() {
s := &http.Server{
Addr: fmt.Sprintf(":%d", 8080),
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
MaxHeaderBytes: 1 << 20, // Max header of 1MB
}

next := addServedHeader
http.HandleFunc("/", makeRequestHandler(next))
log.Fatal(s.ListenAndServe())
}

We can run this by below command.

faas-cli up -f go-microservice.yml

— Your response will look like this.

$  faas-cli up -f go-microservice.yml
[0] > Building go-microservice.
Clearing temporary build folder: ./build/go-microservice/
Preparing: ./go-microservice/ ./build/go-microservice/
Building: localhost:5000/go-microservice:1.0 with dockerfile template. Please wait..
Sending build context to Docker daemon 7.68kB
Step 1/13 : FROM golang:1.10.4-alpine3.8 as build
---> bd36346540f3
Step 2/13 : RUN mkdir -p /go/src/handler
---> Using cache
---> 41771b742138
Step 3/13 : WORKDIR /go/src/handler
---> Using cache
---> ac151ca23319
Step 4/13 : COPY . .
---> Using cache
---> 0a3341d2af2e
Step 5/13 : RUN CGO_ENABLED=0 GOOS=linux go build --ldflags "-s -w" -a -installsuffix cgo -o handler . && go test $(go list ./... | grep -v /vendor/) -cover
---> Using cache
---> 92991031eb2b
Step 6/13 : FROM alpine:3.9
---> 78a2ce922f86
Step 7/13 : RUN apk --no-cache add ca-certificates && addgroup -S app && adduser -S -g app app && mkdir -p /home/app && chown app /home/app
---> Using cache
---> 0859da0160a9
Step 8/13 : WORKDIR /home/app
---> Using cache
---> 5f1498c7bbb0
Step 9/13 : COPY --from=build /go/src/handler/handler .
---> Using cache
---> 232b70435105
Step 10/13 : RUN chown -R app /home/app
---> Using cache
---> d45c326c6576
Step 11/13 : RUN touch /tmp/.lock # Write a health check for OpenFaaS here or in the HTTP server start-up
---> Using cache
---> 1f8118c3b271
Step 12/13 : USER app
---> Using cache
---> 616b2b430d95
Step 13/13 : CMD ["/home/app/handler"]
---> Using cache
---> 4f002caa7740
Successfully built 4f002caa7740
Successfully tagged localhost:5000/go-microservice:1.0
Image: localhost:5000/go-microservice:1.0 built.
[0] < Building go-microservice done in 0.30s.
[0] Worker done.
Total build time: 0.30s[0] > Pushing go-microservice [localhost:5000/go-microservice:1.0].
The push refers to repository [localhost:5000/go-microservice]
84b6a101f13e: Layer already exists
24bb6e3aa142: Layer already exists
8f7644cfa0e9: Layer already exists
f67c1d81b066: Layer already exists
89ae5c4ee501: Layer already exists
1.0: digest: sha256:47c504fea63aecbd70b6f29f41d18f9b6ac3e36b0bf74b6a3e9e86072cdf6628 size: 1367
[0] < Pushing go-microservice [localhost:5000/go-microservice:1.0] done.
[0] Worker done.
Deploying: go-microservice.Deployed. 202 Accepted.
URL: http://127.0.0.1:31112/function/go-microservice

We can check whether the function is deployed correctly by trying below command. It will show the status of our deployment. (Status should be Running). Or else we can check the status from the UI.

$ kubectl get pods -n openfaas-fn 
NAME READY STATUS RESTARTS AGE
go-microservice-8466b7fdb-l9lwb 1/1 Running 0 12m

Then we can curl our endpoint and get the response.

curl -i http://127.0.0.1:31112/function/go-microservice ;echo
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: text/plain; charset=utf-8
Date: Mon, 09 May 2022 20:06:38 GMT
X-Call-Id: e9b5af76-2a95-4107-8d7c-e51c752d3005
X-Served-Date: 2022-05-09 20:06:38.482143283 +0000 UTC m=+465.848986153
X-Start-Time: 1652126798479241355
OK

This invocation can be done using the ui as the previous example.

We can check our deployments in OpenFaas UI and we can check the metrics in Prometheus UI that we have exposed earlier.

Prometheus Graph
Grafana Graph

Now we have setup our openfaas environment and we have deployed our simple go-lang microservice.

We’ll go through some other OpenFaas related learning in next posts. 😁

--

--