Functions-as-a-Service, premiers pas

La nouvelle vague à la mode dont le nom est « Serverless » propose une approche revue et corrigée des architectures SOA. Si comme moi le sujet vous intéresse et que vous souhaitez vous faire une petite idée du comment je vous propose ce petit tutoriel. Sans grande ambition il permet de déployer une infrastructure ServerLess dans une machine virtuelle et de voir comment y déployer et exécuter une fonction ou 2.

L’article ne détaille pas les concepts liés aux infras ServerLess ni aux Functions-as-a-Service. Le lecteur trouvera facilement sur le web tout un tas d’articles traitant de ces sujets. Fn Project publie une bonne introduction sur ces sujets sur son espace Gut Hub.

 

De quoi avons nous besoin ?

Une VM sous Linux avec un accès SSH pour s’y connecter, ainsi que les droits root pour installer une ou 2 bricoles.
C’est tout.

Quelle infra utiliser ?

Souhaitant disposer d’une solution locale aux dépends d’un cloud provider comme AWS (Lambda) je suis parti du projet open source Fn Project disponible sous Git Hub.

Installation et configuration

Installation de Docker

Et oui, Fn Project s’appuie intégralement sur Docker pour ses services et pour vos fonctions.

[pastacode lang= »bash » manual= »sudo%20yum%20update%0Asudo%20yum%20update%20nss%20nss-util%20nspr%0Asudo%20yum%20update%20curl%0Asudo%20yum%20install%20yum-utils%20device-mapper-persistent-data%20lvm2%0Asudo%20yum-config-manager%20–add-repo%20https%3A%2F%2Fdownload.docker.com%2Flinux%2Fcentos%2Fdocker-ce.repo%0Asudo%20yum%20install%20docker-ce%0Asudo%20systemctl%20start%20docker%0Asudo%20systemctl%20enable%20docker%0Asudo%20systemctl%20status%20docker » message= »Installation et configuration Docker CE » highlight= » » provider= »manual »/]

Ajouter l’utilisateur au groupe docker

[pastacode lang= »bash » manual= »sudo%20usermod%20-a%20-G%20docker%20%24USER » message= » » highlight= » » provider= »manual »/]

Création d’un repository privé pour Docker

C’est pas une obligation, vous pouvez utiliser un repo distant, faudra vous y connecter (docker login) avant de réaliser la suite.

[pastacode lang= »bash » manual= »%23user%20root%0Adocker%20run%20-d%20-p%2050000%3A5000%20–restart%20always%20–name%20my-registry%20registry%3Alatest » message= » » highlight= » » provider= »manual »/]

Pour tester la création du repository :

[pastacode lang= »bash » manual= »curl%20http%3A%2F%2Flocalhost%3A50000%2Fv2%2F_catalog » message= » » highlight= » » provider= »manual »/]

En retour, la commande curl doit vous renvoyer la liste des repos (vide) au format json.

[pastacode lang= »bash » manual= »%7B%22repositories%22%3A%5B%5D%7D » message= » » highlight= » » provider= »manual »/]

Installation de l’infrastructure Fn

Tout est prévu par le projet Fn Project. Un script d’installation pour Linux est disponible sous Git Hub.

[pastacode lang= »bash » manual= »sudo%20curl%20-LSs%20https%3A%2F%2Fraw.githubusercontent.com%2Ffnproject%2Fcli%2Fmaster%2Finstall%20%7C%20sh » message= »Installation de l’infra fn » highlight= » » provider= »manual »/]

Démarrage du serveur

[pastacode lang= »bash » manual= »fn%20start » message= » » highlight= » » provider= »manual »/]

Simple et efficace.

Ensuite tout se fait via la commande « fn »

Création de l’application

L’application illustrant cet article est une petite calculatrice qui permet de réaliser des opérations toutes simples sur des entiers. C’est pas l’application de l’année, je le concède mais là n’est pas le propos.

Les fonctions sont écrites en Go histoire de pimenter un peu le sujet. Fn Project supporte Go, Java, Python, Node.js et Ruby.

Création d’un répertoire pour stocker le code source de l’application et des fonctions.

[pastacode lang= »bash » manual= »mkdir%20calculatrice%0Acd%20calculatrice%0Aecho%20’name%3A%20calculatrice’%20%3E%20app.yaml » message= » » highlight= » » provider= »manual »/]

Création des fonctions

Création de 3 fonctions :

  • une fonction racine de l’application (sans nom)
  • Une fonction addition
  • Une fonction soustraction

Par défaut chaque fonction accepte un paramètre « Name » et revoie un message texte « Hello <Name> » ou « Hello World » si le paramètre n’est pas indiqué.

Les échanges avec la fonction se font par défaut au format JSON, ce n’est pas une obligation.

[pastacode lang= »bash » manual= »fn%20init%20–runtime%20go%20–trigger%20http%0Afn%20init%20–runtime%20go%20–trigger%20http%20soustraction%0Afn%20init%20–runtime%20go%20–trigger%20http%20addition » message= » » highlight= » » provider= »manual »/]

Chaque fonction est déclenchée (trigger) par un appel HTTP sur son URL. Pour le moment, Fn Project ne supporte pas d’autre mode de déclenchement.

 

Chaque fonction sera créée dans  un sous-répertoire  de l’application comportant par défaut 3 fichiers :

  • func.go : le code source Go de la fonction
  • func.yaml : les méta-données associées à la fonction
  • Gopkg.toml : Dépendances Go

Codes sources GO

Fonction addition

[pastacode lang= »java » manual= »package%20main%0A%0Aimport%20(%0A%20%20%20%20%20%20%20%20%22context%22%0A%20%20%20%20%20%20%20%20%22encoding%2Fjson%22%0A%20%20%20%20%20%20%20%20%2F%2F%22fmt%22%0A%20%20%20%20%20%20%20%20%22io%22%0A%0A%20%20%20%20%20%20%20%20fdk%20%22github.com%2Ffnproject%2Ffdk-go%22%0A)%0A%0Afunc%20main()%20%7B%0A%20%20%20%20%20%20%20%20fdk.Handle(fdk.HandlerFunc(myHandler))%0A%7D%0A%0Atype%20Params%20struct%20%7B%0A%20%20%20%20%20%20%20%20Operande%20string%0A%20%20%20%20%20%20%20%20Value%20int%0A%7D%0A%0A%0Afunc%20add(a%20int%2C%20b%20int)%20int%20%7B%0A%20%20%20%20%20%20%20%20return%20a%2Bb%0A%7D%0A%0Afunc%20myHandler(ctx%20context.Context%2C%20in%20io.Reader%2C%20out%20io.Writer)%20%7B%0A%20%20%20%20%20%20%20%20var%20p%20Params%0A%20%20%20%20%20%20%20%20dec%20%3A%3D%20json.NewDecoder(in)%0A%20%20%20%20%20%20%20%20var%20result%20int%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20err%20%3A%3D%20dec.Decode(%26p)%3B%20err%20%3D%3D%20io.EOF%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20err%20!%3D%20nil%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20add(result%2C%20p.Value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20msg%20%3A%3D%20struct%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Resultat%20int%20%60json%3Aresult%60%0A%20%20%20%20%20%20%20%20%7D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Resultat%3A%20result%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20json.NewEncoder(out).Encode(%26msg)%0A%7D » message= »Code source de la fonction addition en Go » highlight= » » provider= »manual »/]

Fonction soustraction

[pastacode lang= »java » manual= »package%20main%0A%0Aimport%20(%0A%20%20%20%20%20%20%20%20%22context%22%0A%20%20%20%20%20%20%20%20%22encoding%2Fjson%22%0A%20%20%20%20%20%20%20%20%2F%2F%22fmt%22%0A%20%20%20%20%20%20%20%20%22io%22%0A%0A%20%20%20%20%20%20%20%20fdk%20%22github.com%2Ffnproject%2Ffdk-go%22%0A)%0A%0Afunc%20main()%20%7B%0A%20%20%20%20%20%20%20%20fdk.Handle(fdk.HandlerFunc(myHandler))%0A%7D%0A%0Atype%20Params%20struct%20%7B%0A%20%20%20%20%20%20%20%20Operande%20string%0A%20%20%20%20%20%20%20%20Value%20int%0A%7D%0A%0A%0Afunc%20substract(a%20int%2C%20b%20int)%20int%20%7B%0A%20%20%20%20%20%20%20%20return%20a-b%0A%7D%0A%0Afunc%20myHandler(ctx%20context.Context%2C%20in%20io.Reader%2C%20out%20io.Writer)%20%7B%0A%20%20%20%20%20%20%20%20var%20p%20Params%0A%20%20%20%20%20%20%20%20dec%20%3A%3D%20json.NewDecoder(in)%0A%20%20%20%20%20%20%20%20var%20result%20int%0A%20%20%20%20%20%20%20%20var%20firstOp%20%3D%20true%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20err%20%3A%3D%20dec.Decode(%26p)%3B%20err%20%3D%3D%20io.EOF%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20err%20!%3D%20nil%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(firstOp)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20firstOp%20%3D%20false%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20p.Value%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20substract(result%2C%20p.Value)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20msg%20%3A%3D%20struct%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Resultat%20int%20%60json%3Aresult%60%0A%20%20%20%20%20%20%20%20%7D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Resultat%3A%20result%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20json.NewEncoder(out).Encode(%26msg)%0A%7D%0A » message= »Code source de la fonction soustraction en Go » highlight= » » provider= »manual »/]

Déploiement des fonctions

Déploiement de toutes les fonctions de l’application « calculatrice » dans le repo Docker local :

[pastacode lang= »bash » manual= »fn%20deploy%20–all%20–local » message= » » highlight= » » provider= »manual »/]

 

Quelques commandes utiles

Obtenir de l’aide

[pastacode lang= »bash » manual= »fn%20–help%0Afn%20list%20–help%0A… » message= » » highlight= » » provider= »manual »/]

Liste des applications

[pastacode lang= »bash » manual= »%24%20fn%20list%20apps%0ANAME%20%20%20%20%20%20%20%20%20%20%20%20ID%0Acalculatrice%20%20%20%2001CZ7ZZVKHNG8G00RZJ0000001″ message= » » highlight= » » provider= »manual »/]

Liste des fonction d’une application

[pastacode lang= »bash » manual= »%24%20fn%20list%20fn%20calculatrice%0ANAME%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ID%0Aaddition%20%20%20%20%20%20%20%20addition%3A0.0.2%20%20%20%20%20%20%20%20%20%2001CZ800XGENG8G00RZJ0000002%0Acalculatrice%20%20%20%20calculatrice%3A0.0.2%20%20%20%20%20%2001CZ801NR0NG8G00RZJ0000006%0Asoustraction%20%20%20%20soustraction%3A0.0.2%20%20%20%20%20%2001CZ802DWFNG8G00RZJ000000A » message= » » highlight= » » provider= »manual »/]

Liste des triggers d’une application

[pastacode lang= »bash » manual= »%24%20fn%20list%20tr%20calculatrice%0AFUNCTION%20%20%20%20%20%20%20%20NAME%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ID%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TYPE%20%20%20%20SOURCE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ENDPOINT%0Aaddition%20%20%20%20%20%20%20%20addition-trigger%20%20%20%20%20%20%20%2001CZ80GKYMNG8G00RZJ0000003%20%20%20%20%20%20http%20%20%20%20%2Faddition-trigger%20%20%20%20%20%20%20http%3A%2F%2Flocalhost%3A8080%2Ft%2Fcalculatrice%2Faddition-trigger%0Acalculatrice%20%20%20%20calculatrice-trigger%20%20%20%2001CZ80HCSYNG8G00RZJ0000007%20%20%20%20%20%20http%20%20%20%20%2Fcalculatrice-trigger%20%20%20http%3A%2F%2Flocalhost%3A8080%2Ft%2Fcalculatrice%2Fcalculatrice-trigger%0Asoustraction%20%20%20%20soustraction-trigger%20%20%20%2001CZ82MVHFNG8G00RZJ000000N%20%20%20%20%20%20http%20%20%20%20%2Fsoustraction-trigger%20%20%20http%3A%2F%2Flocalhost%3A8080%2Ft%2Fcalculatrice%2Fsoustraction-trigger%0A » message= » » highlight= » » provider= »manual »/]

Liste des appels effectués vers une fonction

[pastacode lang= »bash » manual= »fn%20list%20calls%20calculatrice%20addition » message= » » highlight= » » provider= »manual »/]

Tests

Il est possible de tester une fonction avec la commande fn invoke.

[pastacode lang= »bash » manual= »%24%20fn%20invoke%20calculatrice%20calculatrice%0Atime%3D%222018-12-22T15%3A34%3A02Z%22%20level%3Dinfo%20msg%3D%22starting%20call%22%20action%3D%22server.handleFnInvokeCall)-fm%22%20app_id%3D01CZ80FF3RNG8G00RZJ0000001%20container_id%3D01CZ8PDTHVNG8G00RZJ000000S%20fn_id%3D01CZ80HCSRNG8G00RZJ0000006%20id%3D01CZ8PDTHVNG8G00RZJ000000R%0A%7B%22message%22%3A%22Hello%20World%22%7D%0A » message= » » highlight= » » provider= »manual »/]

Exemple d’invocation avec paramètres :

[pastacode lang= »bash » manual= »%24%20echo%20-n%20’%7B%22Name%22%3A%22Bob%22%7D’%20%7C%20fn%20invoke%20calculatrice%20calculatrice%0Atime%3D%222018-12-22T15%3A46%3A52Z%22%20level%3Dinfo%20msg%3D%22starting%20call%22%20action%3D%22server.handleFnInvokeCall)-fm%22%20app_id%3D01CZ80FF3RNG8G00RZJ0000001%20container_id%3D01CZ8Q4Z9VNG8G00RZJ0000013%20fn_id%3D01CZ80HCSRNG8G00RZJ0000006%20id%3D01CZ8Q5B3NNG8G00RZJ0000015%0A%7B%22message%22%3A%22Hello%20Bob%22%7D%0A » message= » » highlight= » » provider= »manual »/]

 

Sinon, utiliser curl par exemple pour  tester chaque fonction.

Addition

[pastacode lang= »bash » manual= »%24%20curl%20-d%20’%7B%22Operande%22%3A%22a%22%2C%20%22Value%22%3A40%7D%7B%22Operande%22%3A%22b%22%2C%20%22Value%22%3A10%7D%7B%22Operande%22%3A%22c%22%2C%20%22Value%22%3A50%7D’%20http%3A%2F%2Flocalhost%3A8080%2Ft%2Fcalculatrice%2Faddition-trigger » message= » » highlight= » » provider= »manual »/]

Résultat :

[pastacode lang= »bash » manual= »time%3D%222018-12-22T13%3A28%3A06Z%22%20level%3Dinfo%20msg%3D%22starting%20call%22%20action%3D%22server.handleHTTPTriggerCall)-fm%22%20app_id%3D01CZ80FF3RNG8G00RZJ0000001%20app_name%3Dcalculatrice%20container_id%3D01CZ8F6EGGNG8G00RZJ000000B%20fn_id%3D01CZ80GKYDNG8G00RZJ0000002%20id%3D01CZ8F783ENG8G00RZJ000000E%20trigger_source%3D%2Faddition-trigger%0A%7B%22Resultat%22%3A100%7D » message= » » highlight= » » provider= »manual »/]

Soustraction

[pastacode lang= »bash » manual= »curl%20-d%20’%7B%22Operande%22%3A%22a%22%2C%20%22Value%22%3A40%7D%7B%22Operande%22%3A%22b%22%2C%20%22Value%22%3A10%7D’%20http%3A%2F%2Flocalhost%3A8080%2Ft%2Fcalculatrice%2Fsoustraction-trigger » message= » » highlight= » » provider= »manual »/]

Résultat :

[pastacode lang= »bash » manual= »time%3D%222018-12-22T15%3A19%3A28Z%22%20level%3Dinfo%20msg%3D%22starting%20call%22%20action%3D%22server.handleHTTPTriggerCall)-fm%22%20app_id%3D01CZ80FF3RNG8G00RZJ0000001%20app_name%3Dcalculatrice%20container_id%3D01CZ8NK53HNG8G00RZJ000000P%20fn_id%3D01CZ82MVHANG8G00RZJ000000M%20id%3D01CZ8NK53HNG8G00RZJ000000N%20trigger_source%3D%2Fsoustraction-trigger%0A%7B%22Resultat%22%3A30%7D%0A » message= » » highlight= » » provider= »manual »/]

Enjoy !