Simon Karman, software engineer schreef dit artikel eerder voor Java Magazine.
Het bouwen en onderhouden van een applicatie infrastructuur in een cloud omgeving is een tijdrovend en ingewikkeld process. Een framework dat je in staat stelt om je infrastructuur in een cloud omgeving makkelijk te kunnen beheren, is tegenwoordig een must-have. Een van de technieken die hiervoor veel wordt gebruikt is ‘Infrastructure as Code’.
IaC frameworks gebruiken vaak een dataformaat zoals YAML voor definities van cloud componenten. De laatste jaren worden deze cloud componenten steeds vaker gedefinieerd in source code zoals YAML en TypeScript. In dit artikel vergelijken we het Serverless Framework (YAML) en de AWS Cloud Development Kit (TypeScript) en hoe deze frameworks succesvol kunnen worden toegepast. Bij mijn huidige opdracht ben ik bezig met een transitie van het SF naar de CDK. Alle nieuwe microservices worden met de CDK ontwikkeld en enkele oude microservices worden omgezet van het SF naar de CDK. Hierbij werden de verschillen tussen deze frameworks me heel duidelijk. De inzichten die ik daarbij op deed, wil ik in dit artikel graag met jullie delen.
Serverless Computing
Wanneer je applicaties in de cloud bouwt kun je er voor kiezen om een serverless architectuur te gebruiken. Dit betekent dat je als developer een applicatie aanlevert en dat het cloud platform (grotendeels) zorgt voor het infrastructurele en operationele beheer. In dit artikel ligt de focus op de Amazon Web Services (AWS). Dit is het cloud computing platform van Amazon. Serverless computing maakt gebruikt van bouwblokken, zoals queues, functies, data tabellen, topics, ect. Deze bouwblokken vormen samen jouw applicatie. AWS kent honderden van dit soort bouwblokken genaamd resources, verspreid over verschillende services. Deze resources zul je onder verschillende services moeten aanmaken en onderhouden. Daarnaast wil je een applicatie vaak meerdere keren op precies dezelfde manier aanmaken (bijvoorbeeld op een test- en een productieomgeving). Ten slotte is het belangrijk om overzicht te hebben van welke resources bij welke applicatie horen. Een Infrastructure as Code framework dat geautomatiseerd resources kan aanmaken en onderhouden, vanuit je CI/CD pipeline, is om bovenstaande redenen een must-have. De service die dit biedt binnen AWS is AWS CloudFormation.
AWS CloudFormation
AWS Cloudformation is een vorm van ‘Infrastructure as Code (IaC)’. Het stelt ons in staat om de infrastructuur van een applicaties te beschrijven in code, namelijk in een template. Een template beschrijft de resources die nodig zijn voor onze applicatie. Wanneer je zo’n template uitrolt zullen alle benodigde resources bij de verschillende services van AWS geautomatiseerd worden aangemaakt. Deze resources vormen samen een CloudFormation Stack. Wanneer je de template van een stack wijzigt, zal AWS CloudFormation de wijzigingen toepassen op de resources in de verschillende services van jouw AWS account. Het maken van een template file is complex en templates kunnen duizenden regels lang worden. Gelukkig zijn er frameworks die je helpen bij het maken van deze templates. In dit artikel ligt de focus op twee van deze frameworks, namelijk: het Serverless Framework (SF) en de AWS Cloud Development Kit (CDK). Het doel van beide frameworks is hetzelfde. Het genereren van een CloudFormation template. Het SF gebruikt een configuratie bestand in een tekst data formaat zoals YAML en de CDK gebruikt een programmeertaal zoals Java of TypeScript. We kunnen op basis daarvan het onderscheid maken tussen twee verschillende soort IaC, namelijk ‘Infrastructure as ConfiGuration’ (IaCG) en ‘Infrastructure as Source Code’ (IaSC).
Serverless Framework
Het Serverless Framework (SF) is een IaCG framework, dat je in staat stelt om een serverless applicatie te bouwen, die in de core bestaat uit serverless functies. Je doet dit door een YAML file (serverless.yml) te schrijven. Dit configuratiebestand lijkt erg op een CloudFormation template. Het SF is cloud agnostisch en is dus naast bij AWS ook bruikbaar bij andere cloud providers. Het SF gebruikt een versimpelde notatie om lambda functies te definiëren en deze lambdas direct te integreren met standaard AWS services (zoals een API Gateway). Dit stelt je in staat om vanuit een beknopt configuratiebestand een CloudFormation template van duizenden regels te genereren. Daarnaast maakt het SF het mogelijk om plugins toe te voegen die in kunnen haken op de generatie van de CloudFormation template.
AWS Cloud Development Kit
De Cloud Development Kit (CDK) is een IaSC framework, waarin je jouw applicatie kunt definiëren in klassen en objecten in een programmeertaal zoals Java of TypeScript. De CDK is erop ingericht dat je herbruikbare cloud componenten schrijft, genaamd constructs. Deze constructs zijn samenstelbaar, door middel van compositie. Dit betekent dat een construct kan bestaan uit lager-level constructs, die op hun beurt ook weer kunnen bestaan uit lagere-level constructs, die uiteindelijk cloud resources vertegenwoordigen. In de CDK is de root construct een App, deze app construct bevat een of meerdere stack constructs en deze stack constructs bevatten op hun beurt weer lager-level constructs. De CDK kan vervolgens jouw stacks omzetten in een cloud formation template, dit wordt ‘synthesizen’ genoemd.
Wist je dat de CDK volledig is ontwikkeld in TypeScript?
Meer informatie over JSII kan je vinden op https://github.com/aws/jsii
Vergelijking SF en CDK
Om het SF en de CDK met elkaar te vergelijken kunnen we kijken naar een applicatie die gebouwd is met zowel het SF als de CDK. De applicatie die we gaan bekijken is een serverless rekenmachine. Deze rekenmachine heeft een interne staat die waardes van meerdere tellers kan bijhouden. De waardes van deze tellers kunnen worden verhoogd of verlaagd door middel van api call op een http endpoint. De source code is beschikbaar op: https://github.com/simonkarman/cdk-vs-sf. De infrastructuur van deze applicatie bestaat uit resources in verschillende services van AWS. Ten eerste hebben we een Rest API nodig van de AWS API Gateway service om de http endpoints in te definieren. Daarnaast hebben we meerdere functie resources in de AWS Lambda service nodig voor de afhandeling van de API calls. Ten slotte hebben we een database tabel resource in de DynamoDB service nodig voor het opslaan van de waardes van de verschillende tellers. Uit veiligheidsoverwegingen mogen resources in AWS niet zomaar gebruik maken van andere resources in het account. We moeten er dus zelf voor zorgen dat de lambda functie de benodigde permissies heeft om de tellers aan te passen in de dynamodb tabel. Hiervoor gebruiken we een rol van de IAM service. Een rol omschrijft wat een bepaalde resource wel en niet mag doen in AWS.
Infrastructuur in SF
Het SF gebruikt voor de configuratie van de infrastructuur de taal YAML. Deze configuratie is terug te vinden in het ‘serverless.yml’ bestand (zie afbeelding). Dit bestand heeft veel weg van een CloudFormation template, maar er zijn wat extra secties toegevoegd zoals ‘provider’ en ‘function’. De eerste sectie is de provider. Deze sectie beschrijft globale instellingen voor onze applicatie, zoals de regio waar de applicatie uitgerold moet worden. Het SF framework zorgt er op de achtergrond voor dat er ook een IAM rol wordt aangemaakt die wordt gebruikt wordt door de lambda functies. In de iamRoleStatements kunnen we extra statements toevoegen die aan deze rol moeten worden toegevoegd. In dit geval is dat dus de dynamodb:UpdateItem actie op de tabel.
De tweede sectie is de functions. Hier kunnen we alle lambda functies definiëren die we voor de applicatie nodig hebben. In ons geval is dat er een. De calculator functie staat gedefinieerd in src/calculator.handler en de runtime is nodejs14.x. De namen van de resources, die gebruikt worden in een Lambda functie, kunnen gerefereerd worden en beschikbaar worden gesteld via een environment variable. Ten slotte moeten we in de events aangeven wanneer deze functie moet worden aangeroepen. Hier geven we aan dat wanneer de PUT /calculator resource aangeroepen wordt, de aanroep naar deze lambda moet worden gestuurd. Het SF zal voor ons een Rest API in de API Gateway service aanmaken en dit endpoint daaraan toevoegen. De laatste sectie bevat de resources. In deze sectie kunnen we extra resources definiëren die we nodig hebben voor onze applicatie door middel van het schrijven van pure Cloud Formation. Dit is hetzelfde als wanneer je het SF niet zou gebruiken. In deze sectie maken we de DynamoDB tabel aan waar we eerder al naar verwezen hebben. De verschillende types en properties daarop zijn terug te vinden in de documentatie van AWS CloudFormation.

2
Deze 18 regels TypeScript genereren een AWS CloudFormation template dat 633 regels lang is. Dit is significant groter dan het SF template. De voornamelijkste reden van het verschil is dat de CDK metadata toevoegt aan je CloudFormation template. Uit deze metadata is te herleiden welke resources in je code hebben geleid tot de resources.
Implementatie CDK
De CDK gebruikt voor de configuratie van de infrastructuur TypeScript. Deze configuratie is terug te vinden in het ‘lib/cdk-stack.ts’ bestand (zie afbeelding). In CDK maak je resources aan door een object te instantiëren. De argumenten die je mee moet geven aan de constructor volgen altijd hetzelfde patroon. Het eerste argument is de scope waaronder de resource moet worden aangemaakt. Dit zorgt voor het compositie pattern. Voor de drie resources die we in ons geval nodig hebben is dit steeds de stack en wordt er dus als eerste argument ‘this’ gebruikt. Het tweede argument is het id van de resource. Het derde argument is optioneel en kan gebruikt worden om properties mee te geven. Als eerste maken we de dynamodb tabel aan (regel 12). Hier kunnen we bij het type van de partitionKey gebruik maken van een Enum in plaats van een String om geen spelfouten te maken. Als tweede maken we de lambda functie aan (regel 20). Hier specificeren we, net zoals bij het SF, de environment variabelen, runtime en entry. Nu we zowel de lambda functie als dynamodb tabel hebben, kunnen we de grantWriteData methode op de tabel aanroepen en hier de lambda functie aan meegeven (regel 28). Dit zorgt er voor dat het correcte statement wordt toegevoegd aan de IAM rol van de functie. Ten slotte moeten we de API Gateway aanmaken (regel 31). Hier kunnen we vervolgens de lambda functie toevoegen onder de PUT /calculator resource.
Voor- en nadelen van SF en CDK
Het grootste voordeel van het gebruiken van het SF is dat je over veel van de boilerplate configuratie niet zelf hoeft na te denken. Zo hoef je zelf geen API Gateway te configureren, maar wordt deze in de achtergrond automatisch voor je aangemaakt wanneer je een http event gebruikt in een van je functies. Dit zorgt ervoor dat je een simpele applicatie in enkele regels kunt opzetten. In vergelijking zal een simpele applicatie binnen CDK wat meer configuratie nodig hebben voor lambda functie integraties zoals API Gateway. Dit zorgt er echter wel voor dat het met CDK makkelijker is om deze integraties te configureren zoals je zelf wilt.
Het grootste nadeel van het SF is dat je makkelijk typefoutjes kan maken. Het gebruik van een programmeertaal zoals TypeScript is daarom ook het grootste voordeel van het gebruiken van de CDK. Het belangrijkste hieraan is dat niet alleen jij als developer, maar ook de tools waarmee je werkt, de syntax van deze programmeertalen al kennen. Direct tijdens het schrijven van de configuratie in TypeScript zien we welke eigenschappen er allemaal beschikbaar zijn op een resource door de auto-completion features van je IDE. En misschien nog wel belangrijker, je ziet ook direct welk type er per eigenschap wordt verwacht. Dit scheelt veel tijd aangezien je niet constant de documentatie hoeft te raadplegen. Daarnaast maakt het ook het refactoren van een applicatie makkelijk en veilig. Ook andere intelligente features die IDEs bieden voor programmeertalen, zijn direct beschikbaar. Denk hierbij bijvoorbeeld aan deprecation warnings.
Een ander belangrijk voordeel van de CDK is het compositie model dat wordt gebruikt. Dit model zorgt ervoor, dat je een heeft-een associatie kunt creëren tussen je constructs. Daardoor is het erg makkelijk om componenten die je maakt te hergebruiken. Dit maakt CDK beter schaalbaar dan het SF voor grotere en complexere applicaties.
Nog een belangrijk voordeel van de CDK is, dat je je constructs kunt unit testen. Hierdoor is je development lifecycle korter en kun je sneller fouten detecteren. Je kunt bijvoorbeeld testen of jouw stack een lambda functie aanmaakt en of die de goede environment variabelen mee krijgt. Of dat de S3 bucket die je aanmaakt wel van de goede encryptie is voorzien.
Zowel het SF als het de CDK hebben enkele standaard resources nodig in je AWS account om te kunnen functioneren, zoals een S3 bucket om de source code van je Lambda functies in op te slaan. Het SF gebruikt hiervoor een S3 bucket per applicatie, en voor de CDK moet je eenmalig op je AWS account de CDK toolkit bootstrappen.
Conclusie
In dit artikel hebben we gekeken naar het gebruik van zowel het Serverless Framework (SF) als de AWS Cloud Development Kit (CDK) om een applicatie te bouwen. Het is duidelijk geworden dat de CDK enkele belangrijke voordelen heeft boven het SF, zeker wanneer je grotere en complexere applicaties wilt bouwen. Deze verbeteringen zijn vooral te danken aan het feit dat de CDK een ‘Infrastructure as Source Code` framework is en je je configuratie definieert in een programmeertaal. De belangrijkste voordelen hiervan zijn type safety, herbruikbaarheid en unit testing. Als je zelf ook graag aan de slag wilt gaan met de CDK, dan kan ik je aanraden om eens een simpele applicatie te ontwikkelen met de gratis resources van AWS. Zo kun je de voorbeeld applicatie van https://github.com/simonkarman/cdk-vs-sf verder uitbreiden, of de workshop op cdkworkshop.com volgen.