Construindo nosso próprio serverless baseado em Fn

Construindo nosso próprio serverless baseado em Fn

Computação sem servidor é uma das tendências mais proeminentes na computação em nuvem. O princípio básico de funcionamento é que a infraestrutura não é preocupação do DevOps, mas do provedor de serviços. O escalonamento de recursos se ajusta automaticamente à carga e tem uma alta taxa de alteração.

Outra característica comum é a tendência de minimizar e focar o código, razão pela qual a computação sem servidor às vezes é chamada de função como serviço (FaaS).

Historicamente, o primeiro provedor de nuvem a oferecer FaaS com AWS Lambda foi a Amazon, daí o nome. Outros provedores de serviços em nuvem também oferecem outros semelhantes:

  • Funções de nuvem do Google
  • Funções Azure da Microsoft

Todas essas empresas fornecem computação sem servidor, escalonamento automático e pagam apenas pelo que você realmente usa, mas prendem os clientes a seus produtos proprietários. No entanto, existem alternativas gratuitas e de código aberto para computação sem servidor. Vale a pena notar:

  • Plataforma Apache OpenWhisk, desenvolvido em uma incubadora da IBM,
  • Funções Spring Cloud, como parte de um ecossistema Spring Framework bastante rico, que também pode ser usado como fachada para AWS Lambda, Azure Functions e OpenWhisk,
  • Projeto Fn, suportado pela Oracle.

Todos eles são totalmente independentes de nuvens, ou seja, podem ser instalados em qualquer nuvem, inclusive a sua, pública ou privada, e claro em Exoscale.

Como funciona o projeto Fn

Fn é totalmente baseado em Docker e consiste em dois componentes principais:

  • Programa CLI projetado para gerenciar todos os aspectos da infraestrutura Fn e interagir com o servidor Fn,
  • O próprio servidor Fn é um aplicativo normal empacotado em um contêiner Docker.

As funções implantadas no Fn também são executadas em contêineres separados, o que permite suportar diversas linguagens de programação, por exemplo... Clojure!

Os argumentos da função são passados ​​para a entrada padrão (STDIN), os resultados são gravados na saída padrão (STDOUT). Se os argumentos ou valores de retorno não forem valores simples (como um objeto JSON), eles podem ser convertidos usando uma camada de abstração fornecida pelo próprio Fn na forma de um Kit de Desenvolvimento de Funções (FDK).

Por conveniência, são oferecidos conjuntos integrados de modelos para facilitar a implantação de FaaS em uma extensa lista de diferentes linguagens e suas versões (Go, diferentes versões de Java, Python, etc.).

Criar um FaaS é fácil seguindo este diagrama:

  • Implantando a função usando a CLI Fn: um arquivo de configuração de aplicativo para Fn é criado com base no modelo selecionado.
  • Implementamos nossa própria função, novamente usando CLI Fn: a imagem do contêiner é colocada em um determinado repositório, após o qual o servidor é notificado da existência e posicionamento desta imagem.

Construindo nosso próprio serverless baseado em Fn
O princípio de entregar funções para Fn

Instalação local e teste de funções sem servidor

Vamos começar a instalar o Fn na máquina local. Primeiro, o Docker é instalado conforme exigido por Fn. Supondo que estejamos no Debian/Ubuntu:

$ sudo apt-get update
$ sudo apt-get install docker.io

Ou use um gerenciador de pacotes/construção do Docker de acordo com o seu sistema. Então você pode ir direto para a instalação do Fn CLI. Por exemplo, usando curl:

$ curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

Se você estiver no OSX com o Homebrew instalado, poderá seguir o outro caminho:

$ brew install fn

==> Downloading https://homebrew.bintray.com/bottles/fn-0.5.8.high_sierra.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/b1/b1767fb00e2e69fd9da73427d0926b1d1d0003622f7ddc0dd3a899b2894781ff?__gda__=exp=1538038849~hmac=c702c9335e7785fcbacad1f29afa61244d02f2eebb
######################################################################## 100.0%
==> Pouring fn-0.5.8.high_sierra.bottle.tar.gz
  /usr/local/Cellar/fn/0.5.8: 5 files, 16.7MB

Agora estamos prontos para implantar inicialmente nossa função usando a CLI. Para simplificar, usaremos um ambiente de inicialização integrado, como o Node:

$ fn init --runtime node --trigger http hellonode

Creating function at: /hellonode
Function boilerplate generated.
func.yaml created.

Um novo diretório será criado hellonode para desenvolver ainda mais nossa função Fn com alguns arquivos de configuração básicos. Dentro do diretório recém-criado, você pode criar sua aplicação seguindo os padrões da linguagem ou runtime escolhido:

# Каталог с node выглядит так:

   hellonode
   ├── func.js
   ├── func.yaml
   └── package.json

# Свежеустановленное окружение Java11 такое:

   hellojava11
   ├── func.yaml
   ├── pom.xml
   └── src
       ├── main
       │   └── java
       │       └── com
       │           └── example
       │               └── fn
       │                   └── HelloFunction.java
       └── test
           └── java
               └── com
                   └── example
                       └── fn
                           └── HelloFunctionTest.java

Fn cria a estrutura inicial do projeto, cria um arquivo func.yaml, contendo as configurações necessárias para Fn, e define o modelo para o código no idioma que você escolheu.

No caso do tempo de execução do Node, isso significa:

$ cat hellonode/func.js

const fdk=require('@fnproject/fdk');

fdk.handle(function(input){
  let name = 'World';
  if (input.name) {
    name = input.name;
  }
  return {'message': 'Hello ' + name}
})

Agora testaremos rapidamente nossa função localmente para ver como tudo funciona.

Primeiro, iniciaremos o servidor Fn. Como já mencionado, o servidor Fn é um contêiner Docker, portanto, após a inicialização, ele irá retirar a imagem do registro Docker.

$ fn start -d                    # запускаем локальный сервер в фоне

Unable to find image 'fnproject/fnserver:latest' locally
latest: Pulling from fnproject/fnserver
ff3a5c916c92: Pull complete
1a649ea86bca: Pull complete
ce35f4d5f86a: Pull complete

...

Status: Downloaded newer image for fnproject/fnserver:latest
668ce9ac0ed8d7cd59da49228bda62464e01bff2c0c60079542d24ac6070f8e5

Para executar nossa função, ela deve ser “lançada”. Isto exige имя приложения: Em Fn, todos os aplicativos devem ser especificados como namespaces para funções relacionadas.

Fn CLI irá procurar o arquivo func.yaml no diretório atual que será usado para configurar a função. Então primeiro você precisa ir ao nosso diretório hellonode.

$ cd hellonode
$ fn deploy --app fnexo --local  # выкатываем функцию локально, имя приложения - fnexo.
                                 # параметр local не заливает образ в удаленный реестр,
                                 # запуская его напрямую

Deploying hellonode to app: fnexo
Bumped to version 0.0.2
Building image nfrankel/hellonode:0.0.3 .
Updating function hellonode using image nfrankel/hellonode:0.0.3...
Successfully created app:  fnexo
Successfully created function: hellonode with nfrankel/hellonode:0.0.3
Successfully created trigger: hellonode-trigger

Como você pode ver na saída do comando, uma nova imagem de contêiner Docker é criada contendo nossa função. A função está pronta para ser chamada e temos duas maneiras de fazer isso:

  • usando o comando Fn invoke
  • ligando diretamente via http

Desafio invoke via Fn ele simplesmente emula o trabalho via HTTP para testes, o que é conveniente para testes rápidos:

$ fn invoke fnexo hellonode      # вызываем функцию hellonode приложения fnexo

{"message":"Hello World"}

Para chamar uma função diretamente, você precisa saber a URL completa:

$ curl http://localhost:8080/t/fnexo/hellonode-trigger

{"message":"Hello World"}

O servidor Fn expõe suas funções na porta 8080 e o URL da função parece corresponder ao padrão t/app/function, mas não completamente. Através do HTTP, uma função não é chamada diretamente, mas através de um chamado gatilho, que, segundo o seu nome, “inicia” a chamada da função. Os gatilhos são definidos em `func.yml projeto:

schema_version: 20180708
name: hellonode
version: 0.0.3
runtime: node
entrypoint: node func.js
format: json
triggers:
- name: hellonode-trigger
  type: http
  source: /hellonode-trigger    # URL триггера

Podemos alterar o nome do gatilho para corresponder ao nome da função, isso simplificará tudo:

triggers:
- name: hellonode-trigger
  type: http
  source: /hellonode    # совпадает с именем функции

Em seguida, executamos a entrega da função novamente e a chamamos a partir de um novo gatilho:

$ fn deploy --app fnexo hellonode --local
$ curl http://localhost:8080/t/fnexo/hellonode

{"message":"Hello World"}

Tudo está funcionando! É hora de passar para experimentos em grande escala e publicar nosso FaaS no servidor!

Instalando serviços de função sem servidor em sua própria infraestrutura

Vamos instalar rapidamente uma máquina virtual usando a CLI Exoscale. Se você ainda não configurou, você pode usar nosso guia de início rápido. Essa é uma ferramenta bacana que vai aumentar ainda mais sua produtividade. Não esqueça que você precisa configurar uma regra para abrir a porta 8080 no Grupo de Segurança! Os comandos a seguir iniciarão uma máquina virtual limpa, pronta para hospedar nossas funções:

$ exo firewall create fn-securitygroup
$ exo firewall add fn-securitygroup ssh --my-ip
$ exo firewall add fn-securitygroup -p tcp -P 8080-8080 -c 0.0.0.0/0
$ exo vm create fn-server -s fn-securitygroup

Então você pode fazer ssh na máquina virtual e instalar o servidor Fn remoto:

$ exo ssh fn-server

The authenticity of host '185.19.30.175 (185.19.30.175)' can't be established.
ECDSA key fingerprint is SHA256:uaCKRYeX4cvim+Gr8StdPvIQ7eQgPuOKdnj5WI3gI9Q.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '185.19.30.175' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-20-generic x86_64)

Em seguida instale o Docker e o servidor Fn da mesma forma que já foi feito na máquina local, inicie o servidor:

$ sudo apt-get update
$ sudo apt-get install docker.io
$ sudo systemctl start docker
$ curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
$ sudo fn start

...

    ______
   / ____/___
  / /_  / __ 
 / __/ / / / /
/_/   /_/ /_/
    v0.3.643

Fn está pronto para receber funções! Para transferência direcionada de funções para um servidor remoto, usaremos o comando deploy do computador local omitindo o sinalizador --local.

Além disso, Fn exige que você especifique a localização do servidor Fn e do registro do Docker. Essas opções podem ser definidas por meio de variáveis ​​de ambiente FN_API_URL и FN_REGISTRY respectivamente, mas também oferece uma maneira mais conveniente de gerenciar facilmente a criação e o gerenciamento de configurações para implantação.

Em termos de Fn, a configuração para implantação é chamada context. O seguinte comando criará o contexto:

$ fn create context exoscale --provider default --api-url http://185.19.30.175:8080 --registry nfrankel

Você pode visualizar os contextos disponíveis assim:

$ fn list contexts

CURRENT NAME      PROVIDER      API URL                      REGISTRY
    default       default       http://localhost:8080/
    exoscale      default       http://185.19.30.175:8080    nfrankel

E mude para o contexto que acabou de ser criado assim:

 $ fn use context exoscale

 Now using context: exoscale

A partir daqui, a entrega do recurso Fn baixará imagens do Docker usando a conta DockerHub selecionada (no meu caso - nfrankel) e notifique o servidor remoto (neste exemplo - http://185.19.30.175:8080) sobre a localização e a versão da imagem mais recente que contém sua função.

$ fn deploy --app fnexo .   # выполняется на локальной машине из каталога hellonode

Deploying function at: /.
Deploying hellonode to app: fnexo
Bumped to version 0.0.5
Building image nfrankel/hellonode:0.0.5 .

Finalmente:

$ curl http://185.19.30.175:8080/t/fnexo/hellonode

{"message":"Hello World"}

Construindo nosso próprio serverless baseado em Fn
Ciclo de vida da função em computação sem servidor baseada em Fn

Vantagens da computação sem servidor em sua própria capacidade

A computação sem servidor é uma solução conveniente para implementar rapidamente partes independentes de um aplicativo que interagem com aplicativos ou microsserviços mais complexos.

Muitas vezes, isso se deve ao custo oculto de se apegar ao fornecedor escolhido, o que, dependendo do caso de uso e do volume específico, pode levar a custos mais elevados e flexibilidade reduzida no futuro.

As arquiteturas multinuvem e de nuvem híbrida também sofrem nesse caso, porque você pode facilmente se encontrar em uma situação em que gostaria de usar a computação sem servidor, mas devido às políticas corporativas isso pode não ser possível.

Fn é bastante fácil de usar e pode fornecer quase a mesma interface FaaS, com pouca sobrecarga. Ele elimina qualquer dependência de fornecedor e pode ser instalado localmente ou em qualquer provedor de soluções em nuvem conveniente de sua escolha. Também há liberdade na escolha de uma linguagem de programação.

Este artigo aborda apenas os conceitos básicos do Fn, mas criar seu próprio tempo de execução é bastante simples, e a arquitetura geral pode ser implantada de forma mais ampla usando um balanceador de carga Fn ou colocando o Fn atrás de um proxy para proteção.

Fonte: habr.com

Adicionar um comentário