Sådan bygger en pluggbar Golang-applikation og drage fordel af AWS Lambda Layers.

Golang - hvorfor er det værd at være opmærksom?

Golang er et open source-programmeringssprog designet og implementeret af Google. Det er meget brugt i moderne applikationer, især i skyen. Det er de mest karakteristiske træk er:

  • Golang er statisk skrevet - det giver mindre fleksibilitet, men beskytter dig mod at begå fejl,
  • Det er ikke objektorienteret. Du kan dog oprette strukturer og grænseflader, og det giver dig 3 af 4 OOP-principper: dataabstraktion, indkapsling og polymorfisme. Arv er den eneste, der mangler,
  • Goroutines! - den største implementering af de lystråde, jeg nogensinde har brugt. Det giver dig mulighed for at oprette en ny tråd på en super nem måde ved hjælp af go-operator og kommunikere mellem forskellige goroutiner ved hjælp af kanaler,
  • Det samles til den ene binære med alle afhængigheder - ikke flere pakker 'konflikter!

Personligt betragter jeg Golang som det største sprog, som jeg bruger på daglig basis. Denne artikel handler imidlertid ikke om at oprette din første funktion eller udskrive "Hello World". Jeg vil vise dig lidt mere avancerede ting. Hvis du er nybegynder og vil lære mere om Golang, kan du besøge dens hovedside.

AWS Lambda & Golang

AWS Lambda er en af ​​de mest populære serverløse computertjenester i den offentlige sky, der blev frigivet i november 2014 af Amazon Web Services. Det giver dig mulighed for at køre din kode som svar på begivenheder som DynamoDB, SNS eller HTTP-triggere uden at levere eller administrere servere! Ved du hvad der virkelig er fantastisk? Siden januar 2018 understøtter det Golang runtime. At arbejde med AWS Lambda er virkelig enkelt - upload bare en lynlåsepakke med din kode og alle afhængigheder (enkelt binært, når du bruger Golang).

Spol frem, 4 år senere på 2018 re: Invent AWS frigiver Lambda Layers, der giver dig mulighed for at gemme og administrere data, der er delt på tværs af forskellige funktioner i det enkelte eller endda flere AWS-konti! For eksempel, mens du bruger Python, kan du placere alle afhængigheder i et ekstra lag, som senere kan bruges af andre Lambdas. Det er ikke nødvendigt at lægge forskellige afhængigheder i hver pakke med lynlås! I Golang er verdenssituationen anderledes, da AWS Lambda kræver, at du uploader kompileret binært. Hvordan kan vi drage fordel af AWS Lambda Layers? Svaret er simpelt - opbyg et modulært program ved hjælp af Golang Plugins!

Golang Plugins - en måde at opbygge en modulær applikation

Golang Plugins er den funktion, der er frigivet i Go1.8, der giver dig mulighed for dynamisk at indlæse delte biblioteker (.so-filer). Det giver dig en mulighed for at eksportere noget af din kode til det separate bibliotek eller bruge plugin udarbejdet og udarbejdet af en anden. Det er lovende, men der er et par begrænsninger:

  • Dit plugin skal være et enkelt hovedmodul,
  • Du kan kun indlæse funktioner og variabler, der eksporteres som ELF-symboler,
  • På grund af statisk indtastning skal du kaste hvert indlæst symbol til den rigtige type. I det værste scenario skal du definere den korrekte grænseflade i din kode,
  • Det fungerer kun for Linux og MacOS. Personligt betragter jeg ikke dette som en ulempe :)

Opbygning og test af dit første plugin

Lad os nu oprette vores første plugin. Som et eksempel vil vi oprette et simpelt modul til strengkryptering. Lad os gå tilbage til det grundlæggende og implementere 2 enkle krypteringsalgoritmer - Ceasar og Verman.

  • Caesar-chiffer er den algoritme, der først bruges af Julius Cease. Det skifter hvert bogstav i teksten efter det faste antal positioner. For eksempel, hvis du vil kryptere ordet golang med nøglen 4, får du ktpek. Dekrypteringen fungerer på samme måde. Du skal bare flytte bogstaverne i den modsatte retning.
  • Verman-chiffer ligner Ceaser, baseret på den samme skiftende idé, forskellen er, at du skifter hvert bogstav efter det forskellige antal positioner. For at dekryptere teksten skal du have nøglen, der indeholder de positioner, der bruges til at kryptere teksten. For eksempel, hvis du vil kryptere ordet golang med nøglen [-1, 4, 7, 20, 4, -2], får du fremtid.

Den fulde implementering af dette eksempel er tilgængelig her.

Plugin-implementering

Følgende kodestykke indeholder implementeringen af ​​de to ovenfor nævnte algoritmer. For hver enkelt implementerer vi 2 metoder til kryptering og dekryptering af vores tekst:

Som du kan se, eksporterede vi her 3 forskellige symboler (Golang eksporterer kun disse identifikatorer, der starter med det store bogstav):

  • EncryptCeasar - func (int, streng) streng, der krypterer tekst ved hjælp af Ceasar-algoritme,
  • DecryptCeaser - func (int, streng) streng, der dekrypterer tekst ved hjælp af Caeser-algoritme,
  • VermanCipher - variabel af typen vermanCipher, der implementerer 2 metoder: Krypter: func (streng) streng og Dekrypter: func () (* streng, fejl)

For at kompilere dette plugin skal du køre følgende kommando:

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

Foreløbig er der intet særligt - få enkle funktioner blev oprettet, og et modul blev samlet som et plugin ved at tilføje argumentet -buildmode = plugin.

Indlæs og test plugin

Sjovet begynder, når vi vil bruge kompileret plugin i vores app. Lad os oprette et simpelt eksempel:

Først skal du importere Golang-plugin-pakken. Det indeholder kun to funktioner - den første er til indlæsning af delt bibliotek, og den anden er til at finde et eksporteret symbol. For at indlæse dit bibliotek skal du bruge Åben funktion, som kræver at du leverer stien til dit delte plugin og returnerer variabel af typen Plugin. Hvis det ikke er muligt at indlæse biblioteket (f.eks. Forkert sti eller beskadiget fil) returnerer denne funktion den fejl, der skal håndteres.

Det næste trin er at indlæse hvert eksporteret symbol ved hjælp af opslagsmetoden. En lille ulempe er, at du skal indlæse alle eksporterede funktioner separat. Du kan dog kombinere flere funktioner sammen på samme måde, som det blev gjort for VermanCipher-symbolet. Når du har indlæst alle de symboler, du vil bruge, skal du kaste dem til den rigtige type. Golang er et statisk typisk sprog, så der er ingen anden måde at bruge disse symboler på uden casting. Husk, at når du eksporterer en variabel, der implementerer et par metoder, skal du caste den til den rigtige grænsefladetype (jeg var nødt til at definere krypteringEngine-interface for at håndtere dette). \ Newline \ newline

Brug følgende kommando til at kompilere og køre appen:

gå bygge app.go
./app

I output skal du se den krypterede og dekrypterede tekst som et bevis på, at algoritmen fungerer korrekt.

Brug plugin i AWS lambda

For at bruge vores plugin i AWS Lambda er vi nødt til at foretage et par ændringer i vores applikation:

  • AWS Lambda monterer lag til / opt-biblioteket i lambda-containeren, så vi er nødt til at indlæse vores plugin fra dette bibliotek.
  • Vi er nødt til at oprette en handlerfunktion, der vil blive brugt af Lambda-motoren til at håndtere vores testhændelse.

Følgende uddrag indeholder vores applikation justeret til at blive brugt af Lambda:

Som du kan se, implementeringen ligner meget den foregående. Vi har kun ændret det bibliotek, hvorfra vi indlæste vores plugin, og tilføjet funktionssvaret i stedet for udskrivningsværdier. Hvis du vil lære mere om at skrive Lambdas i golang, kan du tjekke AWS-dokumentationen.

AWS Lambda-implementering

Der er to måder at implementere AWS Lambda-funktioner og lag på. Du kan oprette og uploade en zip-pakke manuelt eller bruge den mere avancerede ramme, hvilket gør det meget lettere og hurtigere. I de fleste af mine projekter bruger jeg Serverless-rammen, så jeg har allerede forberedt den enkle serverless.yml-konfigurationsfil ved hjælp af dette værktøj:

service: cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
udbyder:
  navn: aws
  runtime: go1.x
lag:
  cipherLayer:
    sti: bin / plugin
    compatibleRuntimes:
      - go1.x
funktioner:
  motor:
    handler: bin / cipherEngine
    pakke:
      udelukke:
        - ./**
      omfatte:
        - ./bin/cipherEngine
    lag:
      - {Ref: CipherLayerLambdaLayer}

I lagsafsnittet definerede vi et enkelt lag med stien til det allerede oprettede plugin - det vil blive implementeret sammen med lambda-funktionen. Du kan definere op til 5 forskellige lag, hvilken rækkefølge der virkelig er vigtig. De er monteret i det samme / opt-bibliotek, så lag med det højere antal kan tilsidesætte filer fra de tidligere monterede lag. For hvert lag skal du angive mindst 2 parametre: sti til det bibliotek, der indeholder lagkilde (sti til det binære plugin i dit tilfælde) og listen over kompatible driftstider.

Det næste funktionsafsnit er et sted, hvor du definerer listen over de funktioner, der skal implementeres. For hver funktion skal du mindst give stien til den kompilerede applikation. Derudover skal vi definere lagparameteren med henvisning til det lag, der er defineret ovenfor. Dette vil automatisk knytte laget til vores Lambda-funktion under installationen. Den sjove ting er, at du er nødt til at konvertere dit lambda-lags navn til at være TitleCased og tilføje LambdaLayer-suffikset, hvis du vil henvise til den ressource. Det ser ud til, at det serverløse team implementerede det på denne måde for at løse konflikten under henvisning til den forskellige type ressourcer.

Når vores serverless.yml-konfigurationsfil er klar, er den sidste ting at gøre at kompilere vores app, plugin og distribuere den. Vi kan bruge enkel Makefile til det:

.PHONY: build buildPlugin ren implementering
build:
 dep sikre -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
ren:
 rm -rf ./bin ./vendor Gopkg.lock
implementere: ren buildPlugin build
 sls indsætte - verbose

Du kan opbygge og distribuere din funktion ved at køre følgende kommando:

foretage indsættelse

Test AWS Lambda

Som jeg nævnte tidligere udfører AWS Lambda kode som svar på begivenheden. Vi konfigurerede dog ingen begivenhedsudløsere, så den vil ikke blive påberåbt uden vores hjælp. Vi er nødt til at gøre det manuelt ved hjælp af den serverløse ramme eller awscli-værktøjet:

sls påkalde -f funktionsnavn
aws lambda påberåbe sig - funktionsnavn funktionsnavn output_fil

I svaret skal du se det samme output som før, hvilket beviser, at vores lambda-funktion fungerer korrekt og indlæser plugin fra det ekstra lag. Nu kan du oprette andre funktioner, der bruger det samme lag eller endda dele det med andre AWS-konti.

Resumé

Det var meget sjovt at bruge Golang-moduler og teste, hvordan man integrerer dem med de nyligt frigivne AWS Lambda Layers. Plugin-biblioteket er virkelig fantastisk, men på grund af dets begrænsninger og Golang-specifikation kan det kun bruges i nogle specielle scenarier. Jeg tror, ​​at det for de fleste udviklere, der arbejder med standardprojekter, ikke er nødvendigt eller endda muligt at bruge plugins. Kun to grunde tænker på mig:

  • Implementering af komplicerede algoritmer, der kan bruges af de andre applikationer f.eks. videokodning eller krypteringsalgoritmer.
  • Deling af din algoritme med andre uden at offentliggøre dens kode.