Come rendere qualsiasi app NodeJS senza server

Spero che ami Serverless tanto quanto me perché questo è un altro post su quell'argomento.

Ora, se stiamo parlando di una semplice API REST senza server, la tua configurazione è abbastanza ovvia su AWS: Lambda + API Gateway.

Ma che dire di altri (micro) servizi che il tuo backend potrebbe avere? Sai, non è la migliore idea mettere tutto il codice dell'applicazione in un'unica funzione monolitica AWS Lambda.

La sfida

Vogliamo distribuire facilmente moduli applicativi come microservizi serverless, che devono anche comunicare tra loro. Preferibilmente, la comunicazione tra servizi dovrebbe essere regolata da un qualche tipo di ACL.

Tentativo 1. Gateway API

Questo è il primo pensiero che ho avuto quando stavo cercando di risolvere il problema: esporre tutti i microservizi tramite API Gateway. Il problema è ... Le API create sono pubbliche.

Perché questo è un problema? Ad esempio, non desideriamo disporre di un servizio di fatturazione per essere esposti a tutto il mondo, anche se l'accesso è limitato mediante un qualche tipo di autorizzazione.

Bene, puoi rendere l'API privata, ma i criteri di sicurezza sono piuttosto limitati:

Puoi utilizzare i criteri delle risorse del gateway API per consentire che l'API venga invocata in modo sicuro da:
* utenti da un account AWS specificato
* intervalli di indirizzi IP di origine specificati o blocchi CIDR
* cloud virtuali virtuali (VPC) o endpoint VPC specificati (in qualsiasi account)

Ciò rende piuttosto problematico il controllo delle comunicazioni tra tali servizi. L'unico modo per farlo qui è mettere i servizi in VPC separati, troppo lavoro.

Tentativo 2. Lambda

Perché non inseriamo tutti i microservizi in una AWS Lambda separata? Questo risolverà il problema?

Sì, in realtà sarà un microservizio senza server e sarai in grado di utilizzare i criteri IAM per ottimizzare gli accessi tra i servizi, ma ... Non è "facile".

So che al giorno d'oggi è abbastanza normale avere una minuscola funzione come unità di distribuzione. E nel caso in cui il tuo servizio abbia più di 1 endpoint / metodo / funzione, è considerato accettabile implementarlo come Lambdas multipli.

Ne comprendo i vantaggi, ma sacrifichi la facilità di manutenzione e sviluppo. Inoltre, non mi piace l'idea di avere un servizio distribuito come un insieme di funzioni Lambda. Immagina, diverse funzioni separate relative alla fatturazione? Non è più un contesto limitato. Sebbene ci siano casi in cui tale granularità può essere utile, ma è un caso raro.

Tentativo 3. Lambda grasso

Possiamo effettivamente distribuire un set di endpoint come un singolo Lambda (ovviamente senza usare API Gateway)?

Se potessimo farlo, otterremmo tutti i vantaggi dell'opzione precedente, ma saremmo anche in grado di scegliere la granularità delle nostre unità di distribuzione.

Il modo in cui lo voglio è il seguente: ogni servizio distribuibile dovrebbe essere un semplice vecchio oggetto JS semplice con metodi. Questo è abbastanza banale da ottenere aggiungendo alcune righe di codice colla tra il tuo oggetto e AWS Lambda.

Ecco la mia implementazione: aws-rpc. Questo modulo nodejs espone la funzione lambdaHandler, in cui è appena passato un oggetto, ed è esposto automagicamente a chiunque sia in grado di accedere a Lambda:

importare {lambdaHandler} da 'aws-rpc';
import {TestServiceImpl} da './TestServiceImpl';
// questa è la tua unità di distribuzione
// questo è ciò che specifichi come funzione del gestore Lambda
export const handler = lambdaHandler (new TestServiceImpl ());

Ora puoi semplicemente distribuire "handler" come AWS Lambda. Ecco come invocare i suoi metodi:

importare {TestService} da './TestService';
const client = await createClient  ("LambdaName", "test");
console.log (await client.test ());

Si noti che per poter generare metodi per l'oggetto stub client, è necessario passare tutti i nomi dei metodi a createClient, come abbiamo fatto nell'esempio.

Ciò è necessario perché JS non ha alcuna informazione di runtime sulle interfacce TypeScript. Potrei implementarlo usando classi astratte, ma non mi piace ¯ \ _ (ツ) _ / ¯.

Bonus! Puoi eseguirlo tutto localmente!

Ritengo sia molto importante che l'ambiente di sviluppo locale sia il più confortevole possibile. Questo è il motivo per cui ho anche aggiunto la possibilità di eseguire il servizio e il client localmente senza distribuire nulla su AWS (vedi funzioni runService e createClient). Per esempi, consultare il repository su GitHub.

Sommario

È molto facile perdersi nei servizi offerti dai provider cloud e ingegnerizzare eccessivamente la propria infrastruttura.

Scelgo sempre la soluzione più semplice ed esplicita che mi viene in mente. Inoltre, ricorda sempre che molte tecniche e pratiche possono essere riutilizzate da altre piattaforme (l'idea del grasso NodeJS Lambda è ispirata ai cosiddetti vasetti grassi del mondo Java).

Se ti è piaciuto questo argomento, dai un'occhiata anche a questi:

  • Devi imparare come realizzare la migliore architettura senza server
  • Come creare una pipeline CI / CD Serverless gratuita: 3 semplici esempi
  • Come replicare facilmente DynamoDB tra le regioni
  • Come fare un'applicazione multiregionale (e pagare zero)
  • Rendere qualsiasi Java Web App senza server

Commenti, Mi piace e condivisioni sono molto apprezzati. Saluti!