Come creare un'applicazione Golang innestabile e beneficiare dei livelli AWS Lambda.

Golang - perché merita la tua attenzione?

Golang è un linguaggio di programmazione open source progettato e implementato da Google. È molto usato nelle applicazioni moderne, specialmente nel cloud. Le caratteristiche più caratteristiche sono:

  • Golang è tipicamente statico: offre meno flessibilità, ma ti protegge da errori,
  • Non è orientato agli oggetti. Tuttavia, puoi creare strutture e interfacce e questo ti dà 3 di 4 principi OOP: astrazione dei dati, incapsulamento e polimorfismo. L'eredità è l'unica mancante,
  • Goroutines! - la più grande implementazione dei fili leggeri che abbia mai usato. Ti consente di creare un nuovo thread in modo semplicissimo utilizzando l'operatore go e di comunicare tra diverse goroutine utilizzando canali,
  • Si compila nel singolo binario con tutte le dipendenze - niente più conflitti di pacchetti!

Personalmente, considero Golang come la più grande lingua che uso quotidianamente. Tuttavia, questo articolo non riguarderà la creazione della prima funzione o la stampa di "Hello World". Ti mostrerò cose un po 'più avanzate. Se sei un principiante e vuoi saperne di più su Golang, visita la sua pagina principale.

AWS Lambda e Golang

AWS Lambda è uno dei servizi di elaborazione serverless più popolari nel cloud pubblico, rilasciato a novembre 2014 da Amazon Web Services. Ti permette di eseguire il tuo codice in risposta a eventi come trigger DynamoDB, SNS o HTTP senza provisioning o gestione dei server! Sai cos'è davvero grandioso? Da gennaio 2018 supporta il runtime Golang. Lavorare con AWS Lambda è davvero semplice: basta caricare un pacchetto zippato con il codice e tutte le dipendenze (binario singolo quando si utilizza Golang).

Avanti veloce, 4 anni dopo al 2018 re: Invent AWS rilascia Lambda Layers che ti consente di archiviare e gestire i dati condivisi tra diverse funzioni nei singoli o anche più account AWS! Ad esempio, durante l'utilizzo di Python è possibile inserire tutte le dipendenze in un livello aggiuntivo che può essere successivamente utilizzato da altri Lambdas. Non è più necessario inserire dipendenze diverse in ogni pacchetto zippato! Nel mondo Golang la situazione è diversa in quanto AWS Lambda richiede il caricamento di un file binario compilato. Come possiamo trarre vantaggio dagli AWS Lambda Layer? La risposta è semplice: crea un'applicazione modulare usando i plugin Golang!

Plugin Golang: un modo per creare un'applicazione modulare

Golang Plugins è la funzione rilasciata in Go1.8 che ti consente di caricare dinamicamente librerie condivise (file .so). Ti dà l'opportunità di esportare parte del tuo codice nella libreria separata o utilizzare il plug-in preparato e compilato da qualcun altro. È promettente, tuttavia, ci sono alcune limitazioni:

  • Il tuo plugin deve essere un singolo modulo principale,
  • Puoi caricare solo funzioni e variabili esportate come simboli ELF,
  • A causa della digitazione statica, devi trasmettere ogni simbolo caricato al tipo corretto. Nel peggiore dei casi, devi definire l'interfaccia corretta nel tuo codice,
  • Funziona solo per Linux e MacOS. Personalmente, non lo considero uno svantaggio :)

Costruire e testare il tuo primo plugin

Ora creiamo il nostro primo plug-in. Ad esempio, creeremo un semplice modulo per la crittografia delle stringhe. Torniamo alle basi e implementiamo 2 semplici algoritmi di crittografia: Ceasar e Verman.

  • Caesar cipher è l'algoritmo utilizzato per la prima volta da Julius Ceases. Sposta ogni lettera nel testo in base al numero fisso di posizioni. Ad esempio, se vuoi crittografare la parola golang con il tasto 4 otterrai ktpek. La decrittazione funziona allo stesso modo. Devi solo spostare le lettere nella direzione opposta.
  • Il codice Verman è simile al Ceaser, basato sulla stessa idea mutevole, la differenza è che si sposta ogni lettera in base al diverso numero di posizioni. Per decrittografare il testo è necessario disporre della chiave contenente le posizioni utilizzate per crittografare il testo. Ad esempio, se vuoi crittografare la parola golang con il tasto [-1, 4, 7, 20, 4, -2] otterrai futuro.

L'implementazione completa di questo esempio è disponibile qui.

Implementazione del plugin

Il frammento seguente contiene l'implementazione dei due algoritmi sopra menzionati. Per ognuno implementiamo 2 metodi di crittografia e decrittografia del nostro testo:

Come puoi vedere, abbiamo esportato qui 3 simboli diversi (Golang esporta solo questi identificatori che iniziano con la lettera superiore):

  • EncryptCeasar - stringa func (int, string) che crittografa il testo utilizzando l'algoritmo Ceasar,
  • DecryptCeaser - stringa func (int, string) che decodifica il testo usando l'algoritmo Caeser,
  • VermanCipher - variabile di tipo vermanCipher che implementa 2 metodi: Encrypt: stringa (func) stringa e Decrypt: func () (* stringa, errore)

Per compilare questo plugin devi eseguire il seguente comando:

vai a build -buildmode = plugin -o plugin / cipher.so plugin / cipher.go

Per ora, non c'è niente di speciale: sono state create poche semplici funzioni e un modulo è stato compilato come plugin aggiungendo l'argomento -buildmode = plugin.

Carica e testa il plugin

Il divertimento inizia quando vogliamo usare il plugin compilato nella nostra app. Creiamo un semplice esempio:

Innanzitutto, è necessario importare il pacchetto plugin Golang. Contiene solo due funzioni: la prima serve per caricare la libreria condivisa e la seconda serve per trovare un simbolo esportato. Per caricare la tua libreria devi usare la funzione Apri che richiede di fornire il percorso del tuo plugin condiviso e restituisce una variabile di tipo Plugin. Se non è possibile caricare la libreria (es. Percorso errato o file corrotto) questa funzione restituisce l'errore che deve essere gestito.

Il passaggio successivo consiste nel caricare tutti i simboli esportati utilizzando il metodo di ricerca. Un piccolo inconveniente è che è necessario caricare separatamente tutte le funzioni esportate. Tuttavia, è possibile combinare più funzioni insieme come è stato fatto per il simbolo VermanCipher. Una volta caricati tutti i simboli che si desidera utilizzare, è necessario lanciarli nel tipo corretto. Golang è un linguaggio tipicamente statico, quindi non c'è altro modo di usare questi simboli senza lanciare. Ricorda, quando esporti una variabile che implementa alcuni metodi, devi lanciarla sul tipo di interfaccia corretto (ho dovuto definire la crittografia dell'interfaccia Engine per gestirla). \ Newline \ newline

Per compilare ed eseguire l'app utilizzare il comando seguente:

vai a compilare app.go
./app

Nell'output, dovresti vedere il testo crittografato e decrittografato come una prova che l'algoritmo funziona correttamente.

Usa il plugin in AWS lambda

Per utilizzare il nostro plugin in AWS Lambda è necessario apportare alcune modifiche alla nostra applicazione:

  • AWS Lambda monta i layer nella directory / opt nel contenitore lambda, quindi dobbiamo caricare il nostro plugin da questa directory.
  • Dobbiamo creare una funzione gestore che verrà utilizzata dal motore Lambda per gestire il nostro evento di test.

Il frammento seguente contiene la nostra applicazione adattata per essere utilizzata dalla Lambda:

Come puoi vedere l'implementazione è molto simile alla precedente. Abbiamo modificato solo la directory da cui abbiamo caricato il nostro plugin e aggiunto la risposta della funzione invece di stampare i valori. Se vuoi saperne di più su come scrivere Lambdas in Golang, consulta la documentazione di AWS.

Implementazione di AWS Lambda

Esistono due modi per distribuire funzioni e layer AWS Lambda. È possibile creare e caricare manualmente il pacchetto zippato o utilizzare il framework più avanzato, che lo rende molto più semplice e veloce. Per la maggior parte dei miei progetti, utilizzo il framework Serverless, quindi ho già preparato il semplice file di configurazione serverless.yml usando questo strumento:

servizio: cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
provider:
  nome: aws
  runtime: go1.x
strati:
  cipherLayer:
    percorso: bin / plugin
    compatibleRuntimes:
      - go1.x
funzioni:
  motore:
    gestore: bin / cipherEngine
    pacchetto:
      escludere:
        - ./**
      includere:
        - ./bin/cipherEngine
    strati:
      - {Ref: CipherLayerLambdaLayer}

Nella sezione layer abbiamo definito un singolo layer con il percorso del plug-in già creato: verrà distribuito insieme alla funzione lambda. È possibile definire fino a 5 diversi livelli, l'ordine in cui è davvero importante. Sono montati nella stessa directory / opt, quindi i layer con il numero più alto possono sovrascrivere i file dai layer precedentemente montati. Per ogni livello, è necessario fornire almeno 2 parametri: percorso della directory contenente l'origine del livello (percorso nel file binario del plugin nel proprio caso) e l'elenco dei runtime compatibili.

La sezione successiva delle funzioni è un luogo in cui si definisce l'elenco delle funzioni da distribuire. Per ogni funzione, è necessario fornire almeno il percorso dell'applicazione compilata. Inoltre, a tale scopo, è necessario definire il parametro layer con riferimento al layer definito sopra. Questo attaccherà automaticamente il layer alla nostra funzione Lambda durante la distribuzione. La cosa divertente è che devi convertire il nome del tuo livello lambda in TitleCased e aggiungere il suffisso LambdaLayer se vuoi fare riferimento a quella risorsa. Sembra che il team Serverless lo abbia implementato in questo modo per risolvere il conflitto con riferimento al diverso tipo di risorse.

Una volta che il nostro file di configurazione serverless.yml è pronto, l'ultima cosa da fare è compilare la nostra app, plugin e distribuirla. Possiamo usare Simple Makefile per questo:

.PHONY: build buildPlugin clean deploy
costruire:
 dep assicurano -v
 env GOOS = linux go build -ldflags = "- s -w" -o bin / cipherEngine cipherEngine / main.go
buildPlugin:
 env GOOS = linux go build -ldflags = "- s -w" -buildmode = plugin -o bin / plugin / cipher.so ../plugin/cipher.go
pulito:
 rm -rf ./bin ./vendor Gopkg.lock
deploy: clean buildPlugin build
 sls deploy --verbose

È possibile creare e distribuire la funzione eseguendo il comando seguente:

fare dispiegare

Prova AWS Lambda

Come accennato in precedenza, AWS Lambda esegue il codice nella risposta all'evento. Tuttavia, non abbiamo configurato alcun trigger di evento, quindi non verrà invocato senza il nostro aiuto. Dobbiamo farlo manualmente usando il framework Serverless o lo strumento awscli:

sls invoke -f nome_funzione
aws lambda invoke - nome-funzione nome_funzione output_file

Nella risposta, dovresti vedere lo stesso output di prima, il che dimostra che la nostra funzione lambda funziona correttamente e carica il plug-in dal livello aggiuntivo. Ora puoi creare altre funzioni che utilizzeranno lo stesso livello o addirittura condividerlo con altri account AWS.

Sommario

È stato molto divertente utilizzare i moduli Golang e testare come integrarli con i nuovi livelli AWS Lambda. La libreria di plug-in è davvero fantastica, tuttavia a causa dei suoi limiti e delle specifiche Golang può essere utilizzata solo in alcuni scenari speciali. Penso che per la maggior parte degli sviluppatori che stanno lavorando ai progetti standard non sarà necessario o addirittura possibile utilizzare plug-in. Mi vengono in mente solo due motivi:

  • Implementazione di algoritmi complicati che possono essere utilizzati dalle altre applicazioni ex. codifica video o algoritmi di crittografia.
  • Condividere il tuo algoritmo con gli altri senza pubblicare il suo codice.