Der Weg vom Set-up zur funktionierenden Serverless-Anwendung

Serverless im Start-up – kleiner Scope, große Wirkung

Jonas Schweizer

© Shutterstock / Allexxandar

Eine Serverless Infrastructure bietet eine flexible Ressourcenverwaltung mit einer exakten nutzungsabhängigen Abrechnung. Die Vorteile der Nutzung für Unternehmen liegen damit auf der Hand. Doch wie klappt das Set-up einer funktionierenden Serverless-Anwendung und wie bewährt sich Serverless Computing im praktischen Alltag?

Ein Bild sagt mehr als tausend Worte – und wenn man in Diskussionen über die Unterschiede zwischen etablierten Großunternehmen und Start-ups spricht, dann taucht regelmäßig das Bild von trägen Supertankern und wendigen, kleinen Schnellbooten auf. So weit, so gut. Schaut man sich jedoch die Realität an, sieht man aber, dass die meisten Start-ups zwar tatsächlich kleine Boote sind, die Frage der Wendigkeit und Schnelligkeit jedoch bleibt zum Teil unbeantwortet. Der echte Wille, möglichst schnell ein erstes Produkt zu launchen, fehlt häufig. Einer der Gründe könnte sein, dass viele junge Unternehmen zwar mit frischen Produkt- und Dienstleistungsideen antreten, dabei aber oft wenig Erfahrung mit der Product Delivery haben, also der schlichten Umsetzung Ihrer vielen Ideen.

Es gibt unzählige Technologien, Tools und Methoden, die einem Start-up zu extremer Schnelligkeit verhelfen. Doch es bedarf harter Arbeit, richtig zu priorisieren, zu selektieren, anzuwenden, zu lernen und das Gelernte im Unternehmen und in den Köpfen zu verankern. In einem Start-up ist das die gemeinsame Aufgabe von Produkt- und Entwicklungsverantwortlichen. Nehmen wir das breit diskutierte Thema Serverless Infrastructure. Die Vorteile liegen auf der Hand, doch wie erreicht man das Ziel, so eine Innovation möglichst zielgerichtet und smart im Unternehmen zu etablieren? Das war und ist auch das Ziel der Laserhub GmbH, einem vor zwei Jahren in Stuttgart gegründeten Start-ups. Wir als Gründer entwickelten eine automatisierte digitale Plattform für das Auftrags- und Bestellmanagement in der Blechbranche. Um mit dieser rasch zu wachsen, schnell auf Trends zu reagieren und neue Features zu integrieren, haben wir uns intensiv mit dem Thema Serverless auseinandergesetzt. Dazu muss man wissen, dass wir bereits nach drei Monaten ein funktionierendes Produkt am Markt etablieren konnten. Inzwischen schauen wir auf eine sehr breite Kundenbasis, auf die wir mächtig stolz sind. Da wir aber weiterhin experimentierfreudig sein möchten – bei höchster Zuverlässigkeit für die bestehenden Kunden – bedarf es eines gewissen Fingerspitzengefühls bei der Auswahl, Konzeption und Umsetzung neuer Technologien. Eins dieser Themen war Serverless und ganz konkret Serverless Framework. Wir sehen darin große Chancen und haben uns das Thema deshalb im Detail angeschaut bzw. direkt umgesetzt.

Wer Jonas Schweizer einmal live erleben möchte, der hat auf der Serverless Architecture Conferences 2019 Gelegenheit dazu, die vom 14. bis 16. Oktober in Berlin stattfindet. Dort wird unser Speaker in seiner Session „A startup like way of integrating Serverless Framework, API Gateway and Message Queue to handle WebHooks for 3rd-party Services“ über die im Artikel in ihren Grundzügen angesprochene Thematik in aller Ausführlichkeit referieren und für Fragen zur Verfügung stehen.

Besucht uns auf der Serverless Architecture Conference 2019

Fokus auf Mehrwert und Umsetzbarkeit

Mit dem Thema Serverless kann man unzählige Wochen verbringen, denn die Spielwiese ist inzwischen immens. Wir sind aber keine Forschungsabteilung, sondern ein schnell wachsendes Start-up mit limitierten Ressourcen und sehr ambitionierten Wachstumsplänen. Um uns dem Thema zu nähern, haben wir uns deshalb konkrete Ziele gesetzt:

  • Mit einer Serverless-Lösung beseitigen wir ein akutes und wichtiges Problem (direkter Mehrwert).
  • Durch die Einführung der Lösung ändern wir zunächst nichts am bestehenden Deployment (little Distraction).
  • Wir nutzen die Lösung im Produktivbetrieb, sodass wir aus eigenen Erfahrungen lernen können (Mindset of Continuous Improvement).
  • Die Lösung ist skalierbar und kann auf weitere Kontexte angewendet werden (Skalierbarkeit).

Wir haben uns also ein aktuelles Problem vorgeknöpft: Wie reagieren wir auf Änderungen in angebundenen Drittsystemen? Klar, WebHooks liegen auf der Hand, aber wie garantieren wir, dass die jeweiligen Endpoints auf unserer Seite stets verfügbar sind, ggfs. auf Fehler in der Bearbeitung reagieren und darüber hinaus unterschiedliche Authentifizierungsmöglichkeiten anbieten? Das alles unter der Prämisse, dass ein Drittanbieter die Regeln vorgibt, wie er sich integrieren möchte. In unserem Fall ging es um ein API zur Buchung von Paketdienstleistungen und dieses Problem wollten wir mit neuen Technologien in Angriff nehmen.

Das richtige Tooling

In der Regel, möchte man sich nicht allzu lange mit der Auswahl des perfekten Toolings aufhalten. Für uns war Serverless Framework eine gute Wahl, da es cloudagnostisch ist, einen sehr breiten Funktionsumfang besitzt und ausreichend dokumentiert erscheint. Darüber hinaus waren uns einige Referenzen bekannt, die Serverless Framework im Einsatz haben. Das Serverless-Framework-Set-up ist wirklich sehr einfach. Zunächst einmal gilt es, die CLI zu installieren, diese kennen zu lernen und erste Gehversuche zu starten. Um direkt auch erste Tests deployen zu können, muss man sich mit einem bestehenden Konto bei einem Cloudprovider anmelden, in unserem Fall AWS. Das ging alles sehr gut nach Anleitung.

Natürlich geht das Serverless Framework zunächst einmal davon aus, dass man als Anwender eine singuläre Cloud anbindet. Hierfür stehen eine Reihe von cloudspezifischen Boilerplates zur Verfügung, die die jeweilige Konfiguration direkt mitliefern. Dann kann es auch schon losgehen und man kann eine „Hello World“-Funktion deployen. Ein einfacher Befehl der CLI übernimmt den Build und das Deployment der lokalen Konfiguration in die Cloud:

$ serverless deploy

Man bekommt sofort ein Gefühl dafür, welche Arbeit das Framework übernimmt. Alle cloudproviderspezifischen Zusammenhänge und Abhängigkeiten in der Konfiguration werden einem abgenommen. Das erkennt man am einfachsten, wenn man sich in die Cloudkonsole einloggt (also das Web-UI des jeweiligen Anbieters) und einmal visuell nachvollzieht, welche Ressourcen nun wie zusammen geschaltet sind. Ziel erreicht: Infrastructure as Code – done.

Vom Setup zur Anwendung

Im nächsten Schritt haben wir uns die serverless.yml dann mal im Detail vorgenommen. In dieser Datei werden komplexere Konfigurationen für Infrastruktur und Serverless-Businesslogik abgelegt. Nun muss man wissen, dass Serverless in Funktionen denkt, wir gehen also immer von einer Serverless Function aus (bzw., im AWS-Slang gesprochen, einem Lambda). Diese bekommt einen Namen und später auch eine Businesslogik. Aber wie wird sie zunächst einmal angesprochen bzw. getriggert? Hier kommen Events ins Spiel. Es gibt sehr viele verschiedene Möglichkeiten unsere Funktion anzusprechen.

API Gateway

Da wir unser Ziel mit Hilfe von WebHooks erreichen wollen, setzen wir auf einen REST-Endpunkt. Hierfür müssen wir ein HTTP Event definieren:

events:
  - http:
    path: hooks/shipping
    method: post

Die Umsetzung ist dann straightforward. Wir definieren einen URL und die HTTP-Methode. Das ist auch schon alles. Man sollte sich aber darüber im Klaren sein, was im Hintergrund passiert. Mit einem einfachen serverless deploy bauen wir im Hintergrund einen Endpunkt im AWS API Gateway, der sofort erreichbar und funktionsfähig ist. Side Fact: API Gateway bietet out of the box Test- und Staging-Umgebungen. Abbildung 1 zeigt das Ergebnis in der Konsole.

Abb.1: Ergebnis zum API Gateway in der Konsole

Abb.1: Ergebnis zum API Gateway in der Konsole

Der Funktions-Stub ist auch schnell implementiert. Im Ordner Functions legen wir eine Datei mit entsprechendem Namen ab und stellen eine Funktion mit dem notwendigen API zur Verfügung. Diese Funktion kann jetzt als Einstiegspunkt für jegliche Business Logik verwendet werden.

module.exports.handler = async (event, context, callback) => {
}

WebHook und Integrationspattern
Somit haben wir auf Infrastrukturseite alle Vorbereitungen getroffen, um die WebHook-Integration festzulegen und umzusetzen. Dafür hinterlegen wir unseren URL (aus dem API Gateway) in der Konfiguration der SaaS-Lösung. Das hat zur Folge, dass bei jeder Statusänderung ein HTTP Request an den konfigurierten URL ausgelöst wird. Wie möchte sich der Drittanbieter aber nun authentifizieren? In diesem speziellen Fall geht das sehr einfach über ein statisches Token im URL. Es handelt sich nicht um eine Standardauthentifizierung. Die Funktion kümmert sich also selbst um das Parsen des Tokens.

Es liegt jedoch auf der Hand, dass wir die konfigurierten Tokens nicht als Plain Text ablegen möchten. Entsprechend nutzen wir Umgebungsvariablen, die wir in der Funktion aufrufen können. Hierfür bietet Serverless Framework die Option Key-Value-Paare in der env.yml abzulegen. Listing 1 zeigt einen Beispielausschnitt und wie es möglich ist, globale sowie umgebungsspezifische Variablen anzulegen.

Globals: &globals
  foo: "BAR"
dev:
  <<: *globals
  TOKENS: "egknk8ax5f5weysq9ay4"
prod:
  <<: *globals
  TOKENS: "0cg5ycxq1i6yis2dknyd"

Der Endpunkt ist also vorhanden, Authentifizierung möglich – bleibt noch die Logik. In diesem Fall haben wir uns für eine weitere Abstraktion entschieden. Unsere Funktion schickt eine Message über eine AWS SQS Queue und fertig. Die vorhandene App dient als Message-Handler und verarbeitet alle eingehenden Nachrichten. Abhängig vom Nachrichtentyp werden unterschiedliche Prozesse abgearbeitet. Diese Lösung bietet folgende Vorteile:

  1. Nahezu jedes Backend kann mit entsprechenden Queues umgehen (kein Lock-in).
  2. Sollte eine Verarbeitung der Nachricht zum aktuellen Zeitpunkt nicht möglich sein, können wir Retry-Strategien verwenden.
  3. Unser Worker sind im vorhandenen Repo implementiert und haben Zugriff auf alle bestehenden Ressourcen und Services. Ich muss also keine teure Migration der Businesslogik in die Serverless-Funktion vornehmen und warten.

In Listung 2 sehen wir die Handler-Funktion und in Listing 3 die lib für den Queue Handler.

const jsonResponse = require('../lib/jsonResponse')
const queueHandler = require('../lib/queueHandler')

module.exports.handler = async (event, context, callback) => {
  const tokens = process.env.TOKENS.split(',')
  if (event.queryStringParameters && event.queryStringParameters.token && tokens.includes(event.queryStringParameters.token)) {
    return queueHandler.sendMessage(shippingUpdate, event.body)
    .then(data => {
      return jsonResponse.ok({message: 'success'})
    })
    .catch(e => {
      console.error(e.message)
      return jsonResponse.error({message: e.message})
    })
  } else {
    return jsonResponse.unauthorized()
  }
}
const AWS = require('aws-sdk');

const sqs = new AWS.SQS({
  region: 'eu-central-1'
})

const sqsQueueUrl = process.env.AWS_SQS_QUEUE_URL

async function sendMessage (taskName, body) {
  const params = {
    MessageBody: JSON.stringify({taskName: taskName, body}),
    QueueUrl: sqsQueueUrl
}

return sqs.sendMessage(params).promise()
  .then(data => {
    console.log('Success sending message', taskName, data.MessageId)
    return data
  })
  .catch(err => {
    console.log('Error sending message', err)
  })
}

module.exports = {
  sendMessage
}

Wer aufgepasst hat, dem dürfte aufgefallen sein, dass unsere Funktion indirekt auf eine weitere AWS-Ressource zugreift und entsprechende Berechtigungen benötigt (SQS Queue). Ein Plug-in für das Serverless Framework hält hierfür das Handling von IAM Roles bereit, und auch in diesem Fall findet die Konfiguration über Umgebungsvariablen statt. Eine zusätzliche Konfiguration von IAM Roles ist für jedes Event möglich (serverless.yml):

  iamRoleStatements:
    - Effect: "Allow"
      Action: sqs:SendMessage
      Resource: ${self:provider.environment.AWS_SQS_RESOURCE}

Die Implementierung der Worker-Logik ist wenig spektakulär, sodass ich mir an dieser Stelle die Details spare. In der Abbildung 2 sieht man eine Übersicht des Serverless-Integrationspatterns für WebHooks aus Drittanbietersystemen.

Abb.2: Serverless-Integrationspattern für WebHooks aus Drittanbietersystemen

Abb.2: Serverless-Integrationspattern für WebHooks aus Drittanbietersystemen

Kommen wir noch auf eine weitere Hürde zu sprechen. Wir müssen das API Gateway von außen über einen schönen URL erreichbar machen. Auch für diesen Zweck greifen wir auf ein Serverless-Framework-Plug-in zurück: serverless-domain-manager. Über dieses Plug-in lässt sich eine Domain konfigurieren und über serverless deploy verwalten.

Root-Domain umleiten

Ein kurzer Hinweis sei an dieser Stelle erlaubt: In der Boilerplate-Konfiguration findet sich ein Handler für die hello-Funktion. Diese gibt den Request-Input aus und dient der schnellen Orientierung für Anfänger. Man sollte allerdings nicht vergessen, diesen Endpunkt zu definieren, da sonst wichtige Informationen über den AWS-Account frei zugänglich sind. In unserem Fall haben wir uns für eine einfache Umleitung auf laserhub.com entschieden (Listing 4).

module.exports.hello = async (event, context, callback) => {
  const response = {
    statusCode: 301,
    headers: {
      Location: 'https://www.laserhub.com'
    },
    body: '',
  }

  callback(null, response)
}

Wir haben in diesem Fall lediglich eine Funktion geändert und können sie auch eigenständig deployen. Ein serverless deploy -f hello -s prod schiebt die neue Funktion direkt in die Cloud.

Developerworkflow unter Serverless Framework

Recap: Unsere Funktion bietet die Möglichkeit, beliebigen Node.js-Code auszuführen. Je nachdem, welche Packages unsere Anwendung innerhalb einer Funktion nutzt, werden der Build und damit auch das Deployment größer und zeitaufwändiger. Um einem Serverless-Entwickler auch hier die beste Experience zu bieten, greifen wir ein letztes Mal auf ein Serverless-Framework-Plug-in zurück. Mit Serverless Offline wird eine lokale AWS-Umgebung emuliert, sodass wir die Konfiguration sehr leicht lokal entwickeln können, bevor wir sie auf Staging testen und dann live deployen.

Git

Infrastructure as Code hat neben der einfachen Anwendung noch einen weiteren bestechenden Vorteil: Alle Arbeit lässt sich sauber in Git versionieren und verwalten. Dadurch ist nicht nur eine Kollaboration sehr einfach, auch das Bugtracing und Rollbackhandling ist mit ein paar Git-Befehlen zu realisieren.

Das wars. Mit verhältnismäßig wenig Aufwand und keiner Änderung an der bestehenden Architektur bzw. Businesslogik haben wir eine fertige Serverless-Anwendung realisiert.

Serverless Expert Check 2019

Comprehensive Expert Knowledge For Free

16 experts from all over the world discuss how serverless is changing the way developers, operators, and administrators work. Expand your knowledge with the help of our Serverless Architecture Whitepaper. Stay on top of the latest trends in the field of knative, kubernetes, serverless testing as well as their drawbacks and advantages.

Fazit und Ausblick

Auch wenn wir zwischendurch einige Dinge zu lernen hatten, ist unsere Erfahrung mit dem Serverless Framework sehr positiv. In nur zwei Wochen haben wir die Serverless-Welt betreten, erste Gehversuche unternommen und eine produktive Lösung implementiert. Diese läuft seit ca. sechs Monaten und wurde bisher um einen zusätzlichen Endpunkt erweitert.

Kritisch zu betrachten ist an dieser Stelle möglicherweise die Notwendigkeit vieler Plug-ins. Diese werden häufig von der Community gewartet, sodass für Produktivumgebungen ein gewisses Risiko besteht, dass sie nicht ausreichend betreut werden. Der Serverless-Gedanke ist im Entwicklerteam angekommen und wir evaluieren derzeit weitere Bereiche, bei denen wir auf Serverless-Infrastruktur setzen können. Gerade für sehr kleine und unabhängige Services bietet es sich an, auf jeglichen Applikationsunterbau zu verzichten, und sie stattdessen Serverless zu betreiben. Darüber hinaus spielen wir mit dem Gedanken, auch unsere Serverless-Anwendungen in unsere CI/CD-Strategie mit aufzunehmen.

Geschrieben von
Jonas Schweizer
Jonas Schweizer
Jonas Schweizer studierte Informatik in Konstanz, Limerick und Münster. Er war lange als Softwareentwickler und vier Jahre als Strategieberater tätig. Jetzt ist er Co-Founder und CTO von Laserhub, Digitalenthusiast, Hip-Hop-Fan und stolzer Vater.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: