AxaFrance / SlimFaas

SlimFaas : The slimest and simplest Function As A Service
MIT License
171 stars 7 forks source link
axa faas function green green-software kubernetes library

SlimFaas : The slimest and simplest Function As A Service Continuous Integration Quality Gate Reliability Security Code Corevage

Docker SlimFaas Docker Image Size Docker Image Version

SlimFaas.png

Why use SlimFaas?

slim-faas-ram-cpu.png

Getting Started with Kubernetes

To test slimfaas on your local machine by using kubernetes with Docker Desktop, please use these commands:

git clone https://github.com/AxaFrance/slimfaas.git
cd slimfaas/demo
# Create slimfaas service account and pods
kubectl apply -f deployment-slimfaas.yml
# Expose SlimFaaS service as NodePort or Ingress
kubectl apply -f slimfaas-nodeport.yml
# or
# kubectl apply -f slimfaas-ingress.yml
# Install three instances of fibonacci functions
# fibonacci1, fibonacci2 and fibonacci3
kubectl apply -f deployment-functions.yml
# Install MySql
kubectl apply -f deployment-mysql.yml
# to run Single Page webapp demo (optional) on http://localhost:8000
docker run -p 8000:8000 --rm axaguildev/fibonacci-webapp:latest

Now, you can access your pod via SlimFaas proxy:

Synchronous way:

Asynchronous way:

Just wake up function:

Get function status:

List all function status:

Send event to every function replicas (which deployment subscribe to the event name) in synchronous way:

Single Page WebApp demo:

Enjoy slimfaas!!!!

Getting Started with docker-compose

To test slimfaas on your local machine by using kubernetes with Docker Desktop, please use these commands:

git clone https://github.com/AxaFrance/slimfaas.git
cd slimfaas
docker-compose up

Now, you can access your pod via SlimFaas proxy:

Enjoy slimfaas!!!!

How it works

SlimFaas act as an HTTP proxy with 2 modes:

Synchronous HTTP call

sync_http_call.PNG

Asynchronous HTTP call

async_http_call.PNG

Wake HTTP call

Synchronous Publish HTTP call (events) to every replicas

To publish the message to every replicas in "Ready" state of the function

publish_sync_call.png

How to install

  1. Add SlimFaas annotations to your pods
  2. Add SlimFaas pod
  3. Have fun!

sample-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: fibonacci1
spec:
  selector:
    matchLabels:
      app: fibonacci1
  template:
    metadata:
      labels:
        app: fibonacci1
      annotations:
        # Just add SlimFaas annotation to your pods and that's it !
        SlimFaas/Function: "true"
        SlimFaas/ReplicasMin: "0"
        SlimFaas/ReplicasAtStart: "1"
        SlimFaas/ReplicasStartAsSoonAsOneFunctionRetrieveARequest: "false"
        SlimFaas/TimeoutSecondBeforeSetReplicasMin: "300"
        SlimFaas/NumberParallelRequest : "10"
        SlimFaas/Schedule: |
            {"TimeZoneID":"Europe/Paris","Default":{"WakeUp":["07:00"],"ScaleDownTimeout":[{"Time":"07:00","Value":20},{"Time":"21:00","Value":10}]}}
        SlimFaas/DependsOn: "mysql,fibonacci2" # comma separated list of deployment or statefulset names
        SlimFaas/SubscribeEvents: "Public:my-event-name1,Private:my-event-name2,my-event-name3" # comma separated list of event names
        SlimFaas/DefaultVisibility: "Public" # Public or Private (private can be accessed only by internal namespace https call from pods)
        SlimFaas/UrlsPathStartWithVisibility: "Private:/mypath/subPath,Private:/mysecondpath" # Public or Private (private can be accessed only by internal namespace https call from pods)
    spec:
      serviceAccountName: default
      containers:
        - name: fibonacci1
          image: docker.io/axaguildev/fibonacci:latest
          resources:
            limits:
              memory: "96Mi"
              cpu: "50m"
            requests:
              memory: "96Mi"
              cpu: "10m"
          ports:
            - containerPort: 8080
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: slimfaas
spec:
  replicas: 3
  podManagementPolicy: Parallel
  serviceName: slimfaas
  selector:
    matchLabels:
      app: slimfaas
  template:
    metadata:
      labels:
        app: slimfaas
    spec:
      volumes:
        - name: slimfaas-volume
          emptyDir:
            sizeLimit: 10Mi
      serviceAccountName: admin # Use a service account with admin role
      containers:
        - name: slimfaas
          image: docker.io/axaguildev/slimfaas:latest
          livenessProbe:
            httpGet:
              path: /health
              port: 5000
            initialDelaySeconds: 3
            periodSeconds: 10
            timeoutSeconds: 8
            terminationGracePeriodSeconds: 30
          env:
            - name: BASE_FUNCTION_URL
              value: "http://{function_name}.{namespace}.svc.cluster.local:8080"
            - name: BASE_FUNCTION_POD_URL # require for publish route
              value: "http://{pod_ip}:5000"
            - name: BASE_SLIMDATA_URL
              value: "http://{pod_name}.slimfaas.{namespace}.svc.cluster.local:3262/"  # Don't expose this port, it can also be like "http://{pod_ip}:3262/" but if you can use DNS it's better
            - name: SLIMFAAS_PORTS
              value: "5000" # can be like "5000,6000,7000" if you want to expose more ports
            - name: NAMESPACE
              value: "default"
            - name: SLIMDATA_DIRECTORY
              value: "/database"
            # If you want to send event to an url which is not a SlimFaas function, you can use this env variable
            # use comma to separate event name and url, use => to separate event name and destination url.
            # urls are separated by ;
            #- name: SLIMFAAS_SUBSCRIBE_EVENTS
            #  value: "my-event-name1=>http://localhost:5002;http://localhost:5003,my-event-name2=>http://localhost:5002"
            # If you want to use just one pod for testing purpose, you can use this env variable
            #- name: SLIMDATA_CONFIGURATION
            #  value: |
            #      {"coldStart":"true"}
            # If you are not on kubernetes for example docker-compose, you can use this env variable, but you will lose auto-scale
            #- name: MOCK_KUBERNETES_FUNCTIONS
            #  value: "{"Functions":[{"Name":"fibonacci","NumberParallelRequest":1}],"Slimfaas":[{"Name":"slimfaas-1"}]}"

             # Configure CORS allowed Origins, default is *, you can use a comma separated list example: http://localhost:3000,http://localhost:3001
            #- name: SLIMFAAS_CORS_ALLOW_ORIGIN
            # Optional, longer is the delay, less CPU and RAM is used
            #- name : HISTORY_SYNCHRONISATION_WORKER_DELAY_MILLISECONDS
            #  value : "500" # default equivalent to 0,5 seconds
            # Optional, longer is the delay, less CPU and RAM is used
            #- name : REPLICAS_SYNCHRONISATION_WORKER_DELAY_MILLISECONDS
            #  value : "2000" # default equivalent to 2 seconds
            # Optional, longer is the delay, less CPU and RAM is used
            #- name : SLIM_WORKER_DELAY_MILLISECONDS
            #  value : "50" # default equivalent to 50 milliseconds
            # Optional, longer is the delay, less CPU and RAM is used
            #- name : SCALE_REPLICAS_WORKER_DELAY_MILLISECONDS
            #  value : "1000" # default equivalent to 1 seconds
            # Optional
            # name : TIME_MAXIMUM_WAIT_FOR_AT_LEAST_ONE_POD_STARTED_FOR_SYNC_FUNCTION
            # value : "10000" # default equivalent to 10 seconds
            # Optional
            # name : POD_SCALED_UP_BY_DEFAULT_WHEN_INFRASTRUCTURE_HAS_NEVER_CALLED
            # value : "false" # default equivalent to false
            # Optional
            # name : SLIMFAAS_ALLOW_UNSECURE_SSL
            # value : "false" # default equivalent to false
            # Optional
            # name: HEALTH_WORKER_DELAY_MILLISECONDS
            # value: "1000" # default equivalent to 1 seconds
            # Optional
            # name: HEALTH_WORKER_DELAY_TO_EXIT_SECONDS
            # value: "60" # default equivalent to 10 seconds

            # name : SLIMDATA_CONFIGURATION # represent SlimData internal configuration, more documentation here: https://dotnet.github.io/dotNext/features/cluster/raft.html
            # value : | #default values
            #    {
            #      "partitioning":"false",
            #      "lowerElectionTimeout":"150",
            #      "upperElectionTimeout":"300",
            #      "requestTimeout":"00:00:00.3000000",
            #      "rpcTimeout":"00:00:00.1500000",
            #      "coldStart":"false",
            #      "requestJournal:memoryLimit":"5",
            #      "requestJournal:expiration":"00:01:00",
            #      "heartbeatThreshold":"0.5",
            #   }
          volumeMounts:
            - name: slimfaas-volume
              mountPath: /database
          resources:
            limits:
              memory: "76Mi"
              cpu: "400m"
            requests:
              memory: "76Mi"
              cpu: "250m"
          ports:
            - containerPort: 5000
            - containerPort: 3262
  # You can use this section to define a persistent volume claim
  #volumeClaimTemplates:
  #- metadata:
  #    name: slimfaas-volume
  #  spec:
  #    accessModes: [ "ReadWriteOnce" ]
  #    storageClassName: managed-csi # or any other storage class available in your cluster
  #    volumeMode: Filesystem
  #    resources:
  #      requests:
  #        storage: 10Mi
---
apiVersion: v1
kind: Service
metadata:
    name: slimfaas
spec:
    selector:
        app: slimfaas
    ports:
        - name: "http"
          port: 80
          targetPort: 5000
        - name: "slimdata"
          port: 3262
          targetPort: 3262

[!WARNING] Yours service name must be the same as the SlimFaas Deployment/StatefulSet name

SlimFaas Annotations with defaults values

{
  "TimeZoneID":"Europe/Paris", # Time Zone ID can be found here: https://nodatime.org/TimeZones
  "Default":{
    "WakeUp":["07:00"], // Wake up your infrastructure at 07:00
    "ScaleDownTimeout":[
              {"Time":"07:00","Value":20}, // Scale down after 20 seconds of inactivity after 07:00
              {"Time":"21:00","Value":10} // Scale down after 10 seconds of inactivity after 21:00
            ]
  }
}

Why SlimFaas?

We used OpenFaas for a long time and we love it. But we encountered many OpenFaas issues:

We would like to use Knative but:

So we decided to create SlimFaas to have a quick and simple replacement proxy solution that can expose Prometheus metrics. Now we have a solution not coupled to anything. SlimFaas is simple, light, fast and plug and play!

How it works ?

Instead of creating many pods, SlimFaas use internally many workers in the same pod:

SlimData is a simple redis like database included inside SlimFaas executable. It is based on Raft algorithm offered by awesome https://github.com/dotnet/dotNext library. By default, SlimData use a second HTTP port 3262 to expose its API. Don't expose it and keep it internal.

SlimFaas requires at least 3 nodes in production. 2 nodes are required to keep the database in a consistent state.

slimdata.PNG

If you want to use just one pod for testing purpose, you can use this env variable:

This will allow to start a pod alone as a leader. SlimFaas can to scale up and down by using classic Horizontal Pod Autoscaler (HPA).

Build with .NET

Why .NET?

Videos

What Next?

  1. Scale up dynamically from SlimFaas
  2. Wake up from External Source (example: Kafka, etc.)
  3. Continue Optimization