So erstellen Sie eine steckbare Golang-Anwendung und profitieren von AWS Lambda Layers.

Golang - warum ist es Ihre Aufmerksamkeit wert?

Golang ist eine Open-Source-Programmiersprache, die von Google entwickelt und implementiert wurde. Es wird in modernen Anwendungen sehr häufig verwendet, insbesondere in der Cloud. Es sind die charakteristischsten Merkmale:

  • Golang ist statisch geschrieben - es bietet weniger Flexibilität, schützt Sie jedoch vor Fehlern,
  • Es ist nicht objektorientiert. Sie können jedoch Strukturen und Schnittstellen erstellen, und dies ergibt 3 von 4 OOP-Prinzipien: Datenabstraktion, Kapselung und Polymorphismus. Es fehlt nur noch die Vererbung,
  • Goroutinen! - Die beste Umsetzung der Lichtfäden, die ich je verwendet habe. Mit dem go-Operator können Sie ganz einfach einen neuen Thread erstellen und über Kanäle zwischen verschiedenen Goroutinen kommunizieren.
  • Es wird mit allen Abhängigkeiten in die einzelne Binärdatei kompiliert - keine Paketkonflikte mehr!

Ich persönlich betrachte Golang als die größte Sprache, die ich täglich verwende. In diesem Artikel geht es jedoch nicht darum, Ihre erste Funktion zu erstellen oder "Hello World" zu drucken. Ich werde dir ein bisschen fortgeschritteneres Zeug zeigen. Wenn Sie Anfänger sind und mehr über Golang erfahren möchten, besuchen Sie bitte die Hauptseite.

AWS Lambda & Golang

AWS Lambda ist einer der beliebtesten serverlosen Rechendienste in der öffentlichen Cloud, der im November 2014 von Amazon Web Services veröffentlicht wurde. Sie können Ihren Code als Reaktion auf Ereignisse wie DynamoDB-, SNS- oder HTTP-Trigger ausführen, ohne Server einrichten oder verwalten zu müssen! Weißt du was wirklich toll ist? Seit Januar 2018 unterstützt es die Golang-Laufzeit. Die Arbeit mit AWS Lambda ist wirklich einfach - laden Sie einfach ein komprimiertes Paket mit Ihrem Code und allen Abhängigkeiten hoch (einzelne Binärdatei bei Verwendung von Golang).

Schneller Vorlauf, 4 Jahre später, 2018 re: Invent AWS veröffentlicht Lambda Layers, mit denen Sie Daten speichern und verwalten können, die für verschiedene Funktionen in einem oder sogar mehreren AWS-Konten freigegeben sind! Wenn Sie beispielsweise Python verwenden, können Sie alle Abhängigkeiten in eine zusätzliche Ebene einfügen, die später von anderen Lambdas verwendet werden kann. Es ist nicht mehr erforderlich, in jedes gezippte Paket unterschiedliche Abhängigkeiten einzufügen! In der Golang-Welt ist die Situation anders, da AWS Lambda das Hochladen kompilierter Binärdateien erfordert. Wie können wir von den AWS Lambda Layern profitieren? Die Antwort ist einfach - erstellen Sie eine modulare Anwendung mit Golang Plugins!

Golang Plugins - eine Möglichkeit, eine modulare Anwendung zu erstellen

Golang Plugins ist die in Go1.8 veröffentlichte Funktion, mit der Sie gemeinsam genutzte Bibliotheken (.so-Dateien) dynamisch laden können. Sie haben die Möglichkeit, einen Teil Ihres Codes in die separate Bibliothek zu exportieren oder das Plugin zu verwenden, das von einer anderen Person erstellt und kompiliert wurde. Es ist jedoch vielversprechend, dass es einige Einschränkungen gibt:

  • Ihr Plugin muss ein einzelnes Hauptmodul sein,
  • Sie können nur Funktionen und Variablen laden, die als ELF-Symbole exportiert werden.
  • Aufgrund der statischen Typisierung müssen Sie jedes geladene Symbol in den richtigen Typ umwandeln. Im schlimmsten Fall müssen Sie die richtige Schnittstelle in Ihrem Code definieren,
  • Es funktioniert nur unter Linux und MacOS. Persönlich betrachte ich das nicht als Nachteil :)

Erstellen und testen Sie Ihr erstes Plugin

Jetzt erstellen wir unser erstes Plugin. Als Beispiel erstellen wir ein einfaches Modul für die Zeichenkettenverschlüsselung. Kehren wir zu den Grundlagen zurück und implementieren zwei einfache Verschlüsselungsalgorithmen - Ceasar und Verman.

  • Caesar-Chiffre ist der Algorithmus, der zuerst von Julius Ceases verwendet wird. Es verschiebt jeden Buchstaben im Text um die festgelegte Anzahl von Stellen. Wenn Sie zum Beispiel das Wort golang mit dem Schlüssel 4 verschlüsseln möchten, erhalten Sie ktpek. Die Entschlüsselung funktioniert auf die gleiche Weise. Sie müssen nur die Buchstaben in die entgegengesetzte Richtung verschieben.
  • Die Verman-Chiffre ähnelt der Ceaser-Chiffre, basiert auf derselben Verschiebungsidee. Der Unterschied besteht darin, dass Sie jeden Buchstaben um die unterschiedliche Anzahl von Positionen verschieben. Um den Text zu entschlüsseln, benötigen Sie den Schlüssel mit den Positionen, an denen der Text verschlüsselt wurde. Wenn Sie zum Beispiel das Wort golang mit dem Schlüssel [-1, 4, 7, 20, 4, -2] verschlüsseln möchten, erhalten Sie Zukunft.

Die vollständige Implementierung dieses Beispiels finden Sie hier.

Plugin-Implementierung

Das folgende Snippet enthält die Implementierung der beiden oben genannten Algorithmen. Für jede implementieren wir zwei Methoden zum Verschlüsseln und Entschlüsseln unseres Textes:

Wie Sie sehen, haben wir hier 3 verschiedene Symbole exportiert (Golang exportiert nur diese Bezeichner, die mit dem oberen Buchstaben beginnen):

  • EncryptCeasar - func (int, string) String, der Text mit dem Ceasar-Algorithmus verschlüsselt.
  • DecryptCeaser - func (int, string) String, der Text mit dem Caeser-Algorithmus entschlüsselt,
  • VermanCipher - Variable vom Typ vermanCipher, die 2 Methoden implementiert: Encrypt: func (string) string und Decrypt: func () (* string, error)

Um dieses Plugin zu kompilieren, müssen Sie folgenden Befehl ausführen:

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

Im Moment gibt es nichts Besonderes - es wurden nur wenige einfache Funktionen erstellt und ein Modul als Plugin kompiliert, indem das Argument -buildmode = plugin hinzugefügt wurde.

Plugin laden und testen

Der Spaß beginnt, wenn wir das kompilierte Plugin in unserer App verwenden möchten. Lassen Sie uns ein einfaches Beispiel erstellen:

Zuerst müssen Sie das Golang-Plugin-Paket importieren. Es enthält nur zwei Funktionen - die erste dient zum Laden einer gemeinsam genutzten Bibliothek und die zweite zum Auffinden eines exportierten Symbols. Um Ihre Bibliothek zu laden, müssen Sie die Open-Funktion verwenden, für die der Pfad zu Ihrem freigegebenen Plugin und die Rückgabevariable vom Typ Plugin angegeben werden müssen. Wenn das Laden der Bibliothek nicht möglich ist (z. B. falscher Pfad oder beschädigte Datei), gibt diese Funktion den Fehler zurück, der behandelt werden muss.

Der nächste Schritt besteht darin, jedes exportierte Symbol mit der Lookup-Methode zu laden. Ein kleiner Nachteil ist, dass Sie jede exportierte Funktion separat laden müssen. Sie können jedoch mehrere Funktionen auf dieselbe Weise miteinander kombinieren, wie dies für das VermanCipher-Symbol geschehen ist. Nachdem Sie alle Symbole geladen haben, die Sie verwenden möchten, müssen Sie sie in den richtigen Typ umwandeln. Golang ist eine statisch typisierte Sprache, daher gibt es keine andere Möglichkeit, diese Symbole ohne Casting zu verwenden. Denken Sie daran, wenn Sie eine Variable exportieren, die einige Methoden implementiert, müssen Sie sie in den richtigen Schnittstellentyp umwandeln (ich musste die encryptionEngine-Schnittstelle definieren, um dies zu handhaben). \ Newline \ newline

Verwenden Sie den folgenden Befehl, um die App zu kompilieren und auszuführen:

go build app.go
./app

In der Ausgabe sollten Sie den verschlüsselten und entschlüsselten Text als Beweis dafür sehen, dass der Algorithmus ordnungsgemäß funktioniert.

Verwenden Sie das Plugin in AWS Lambda

Um unser Plugin in AWS Lambda zu verwenden, müssen wir einige Änderungen in unserer Anwendung vornehmen:

  • AWS Lambda hängt Layer in das Verzeichnis / opt im Lambda-Container ein, sodass wir unser Plugin aus diesem Verzeichnis laden müssen.
  • Wir müssen eine Handlerfunktion erstellen, die von der Lambda-Engine verwendet wird, um unser Testereignis zu verarbeiten.

Das folgende Snippet enthält unsere Anwendung, die angepasst wurde, um vom Lambda verwendet zu werden:

Wie Sie sehen, ist die Implementierung der vorherigen sehr ähnlich. Wir haben nur das Verzeichnis geändert, aus dem wir unser Plugin geladen haben, und die Funktionsantwort hinzugefügt, anstatt Werte auszudrucken. Weitere Informationen zum Schreiben von Lambdas in Golang finden Sie in der AWS-Dokumentation.

AWS Lambda-Bereitstellung

Es gibt zwei Möglichkeiten, AWS Lambda-Funktionen und -Schichten bereitzustellen. Sie können ein komprimiertes Paket manuell erstellen und hochladen oder das erweiterte Framework verwenden, wodurch es viel einfacher und schneller wird. Für die meisten meiner Projekte verwende ich das Serverless-Framework. Daher habe ich die einfache Konfigurationsdatei serverless.yml bereits mit diesem Tool vorbereitet:

Dienst: cipherService
frameworkVersion: "> = 1.28.0 <2.0.0"
Anbieter:
  Name: aws
  Laufzeit: go1.x
Lagen:
  cipherLayer:
    Pfad: bin / plugin
    kompatibleLaufzeiten:
      - go1.x
Funktionen:
  Motor:
    Handler: bin / cipherEngine
    Paket:
      ausschließen:
        - ./**
      umfassen:
        - ./bin/cipherEngine
    Lagen:
      - {Ref: CipherLayerLambdaLayer}

Im Layerbereich haben wir einen einzelnen Layer mit dem Pfad zum bereits erstellten Plugin definiert - dieser wird zusammen mit der Lambda-Funktion bereitgestellt. Sie können bis zu 5 verschiedene Ebenen definieren, deren Reihenfolge wirklich wichtig ist. Sie werden in dasselbe / opt-Verzeichnis gemountet, sodass Layer mit der höheren Nummer Dateien aus den zuvor gemounteten Layern überschreiben können. Für jede Ebene müssen Sie mindestens 2 Parameter angeben: Pfad zum Verzeichnis mit der Ebenenquelle (in Ihrem Fall Pfad zur Plug-in-Binärdatei) und die Liste der kompatiblen Laufzeiten.

Der nächste Funktionsabschnitt ist ein Ort, an dem Sie die Liste der Funktionen definieren, die implementiert werden sollen. Für jede Funktion müssen Sie mindestens den Pfad zur kompilierten Anwendung angeben. Darüber hinaus müssen wir den Layer-Parameter unter Bezugnahme auf den oben definierten Layer definieren. Dadurch wird die Ebene während der Bereitstellung automatisch an unsere Lambda-Funktion angehängt. Das Lustige ist, dass Sie Ihren Lambda-Ebenennamen in TitleCased konvertieren und das LambdaLayer-Suffix hinzufügen müssen, wenn Sie auf diese Ressource verweisen möchten. Es scheint, dass das Serverless-Team es auf diese Weise implementiert hat, um den Konflikt in Bezug auf die verschiedenen Arten von Ressourcen zu lösen.

Sobald unsere Konfigurationsdatei serverless.yml fertig ist, müssen Sie als Letztes unsere App kompilieren, einstecken und bereitstellen. Dafür können wir einfaches Makefile verwenden:

.PHONY: Build BuildPlugin sauber bereitstellen
bauen:
 dep sichern -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
reinigen:
 rm -rf ./bin ./vendor Gopkg.lock
deploy: clean buildPlugin build
 sls deploy --verbose

Sie können Ihre Funktion erstellen und bereitstellen, indem Sie den folgenden Befehl ausführen:

bereitstellen

Testen Sie AWS Lambda

Wie bereits erwähnt, führt AWS Lambda Code in der Antwort auf das Ereignis aus. Wir haben jedoch keine Ereignisauslöser konfiguriert, sodass sie nicht ohne unsere Hilfe aufgerufen werden können. Wir müssen es manuell mit dem Serverless Framework oder dem awscli Tool machen:

sls ruft -f Funktionsname auf
aws lambda invoke - Funktionsname Funktionsname Ausgabedatei

In der Antwort sollten Sie die gleiche Ausgabe wie zuvor sehen, was beweist, dass unsere Lambda-Funktion korrekt funktioniert und das Plugin aus der zusätzlichen Ebene lädt. Jetzt können Sie andere Funktionen erstellen, die denselben Layer verwenden oder ihn sogar für andere AWS-Konten freigeben.

Zusammenfassung

Es hat viel Spaß gemacht, Golang-Module zu verwenden und zu testen, wie sie in die neu veröffentlichten AWS Lambda Layers integriert werden können. Die Plugin-Bibliothek ist wirklich großartig, kann jedoch aufgrund ihrer Einschränkungen und der Golang-Spezifikation nur in bestimmten Szenarien verwendet werden. Ich denke, dass für die meisten Entwickler, die an den Standardprojekten arbeiten, keine Plugins erforderlich oder sogar möglich sind. Mir fallen nur zwei Gründe ein:

  • Implementierung komplizierter Algorithmen, die von den anderen Anwendungen verwendet werden können, z. Videokodierungs- oder Verschlüsselungsalgorithmen.
  • Teilen Sie Ihren Algorithmus mit anderen, ohne den Code zu veröffentlichen.