IaC-Lösungen für AWS Cloud 2020: Welche ist die richtige für Sie?

Während meiner Tätigkeit als Cloud Berater hatte ich die Gelegenheit mehrere Infrastruktur-as-Code (IAC) Ansätze für Amazon Web Service (AWS) hands-on einzusetzen. Lassen Sie mich meine Erkenntnisse mit Ihnen teilen. Dieser Leitfaden […]

Ein High Level Vergleich der verschiedenen IaC Lösungen und wie sie mit AWS zusammenhängen

Während meiner Tätigkeit als Cloud Berater hatte ich die Gelegenheit mehrere Infrastruktur-as-Code (IAC) Ansätze für Amazon Web Service (AWS) hands-on einzusetzen. Lassen Sie mich meine Erkenntnisse mit Ihnen teilen.

Dieser Leitfaden konzentriert sich auf den Marktführer AWS, da dieser über die größte Vielfalt an IaC-Frameworks verfügt. Wenn Sie Azure- oder Google-Cloud oder eine Mischung aus allen Anbietern verwenden, können Sie diesen Artikel überspringen und mit dem Lernen von terraform beginnen.

Sie kennen vermutlich das User Interface von AWS zur Interaktion mit Cloud-Diensten, die sogenannte AWS „Konsole“. Diese ist sehr nützlich um eine visuelle Darstellung über die Dienste und deren Monitoring Daten zu erhalten.

Auch die manuelle Manipulation des Zustands der Dienste (Starten, Stoppen, Aktualisieren, Konfigurieren) ist möglich, wird aber bei Implementierungen größerer Anwendungen schnell zeitaufwändig und unüberschaubar.

Infrastruktur als Code(IaC) oder:

„…eine einzelne textbasierte Beschreibung einer vollständigen Cloud-Infrastruktur zu einem gegebenen Zeitpunkt“

beseitigt diese Probleme, indem es über ein Versionskontrollsystem wie GIT versionierbar ist und automatisch, ohne weiteren manuellen Aufwand über einen CI-Service wie CodePipeline, bereitgestellt werden kann. Die Open-Source-Community hat bereits mehrere Lösungen zur Verwaltung von IaC für Cloud-Ressourcen herausgebracht:

AWS CloudFormation

Das älteste und mittlerweile etablierteste IaC Framework für Amazon Web Services heißt CloudFormation. Dabei handelt es sich um eine deklarative Spezifikation, die Ihre gesamte Cloud-Infrastruktur in einer oder mehreren .yaml-Dateien beschreibt. Sie können so genannte „Stacks“ verwenden, um die Bereitstellung Ihrer Infrastruktur zu modularisieren, und Sie finden auf der Website von AWS verschiedene Vorlagen dieser Stacks für fast jeden von AWS angebotenen Dienst. Heutzutage ist es jedoch sehr selten, dass ein Entwicklungsingenieur ein „rohes“ CloudFormation-Skript von Hand schreibt, da es doch einige Nachteile gibt, die ich im Folgenden erläutern will.

Da eine Beispiel-CloudFormation-Datei für eine einfache Bereitstellung zu lang war, um sie hier einzufügen, möchte ich Ihnen einen Link zu einem github-Repository mit einem guten Beispiel zur Verfügung stellen

Vorteile

Nachteile

Im Gegensatz zu Programmiersprachen, in denen Sie eine klare Unterscheidung zwischen sprachspezifischer Syntax und Ihrer eigenen benutzerdefinierten Logik haben, verwenden CloudFormation-spezifische Anweisungen (d.h. „Parameter“, „Ref“) die gleiche Syntax wie Attribute, die als Definition für die jeweiligen Services dienen (d.h. „InstanceType“ für eine EC2-Instanz). Das macht es für einen menschlichen Leser sehr schwer, Muster zu unterscheiden und Strukturen zu finden.

Empfehlung:

Die Kernidee von CloudFormation ist immer noch sehr ordentlich, aber es gibt inzwischen eine Vielzahl anderer Lösungen, die in der Open-Source-Gemeinschaft etabliert und von AWS anerkannt sind und die Komplexität der Vorlagen für CloudFormation beseitigen. Am wichtigsten ist, dass die direkte Verwendung von CloudFormation Sicherheitsrisiken mit sich bringen könnte, einfach weil die Komplexität und Wiederholbarkeit von CloudFormation menschliches Versagen begünstigt. Daher ist es ein mutiger Schritt, im Jahr 2020 CloudFormation direkt für die Verwaltung Ihrer Cloud-Infrastruktur im Code zu verwenden, außer vielleicht zur Fehlersuche. Ziehen Sie in Betracht, stattdessen eine der folgenden Lösungen zu verwenden.

AWS-Amplify

Ein CLI-basiertes Framework zur Entwicklung von Cloud-nativen Apps. Dabei ist das Rollout von Cloud-Ressourcen nur eine der vielen Fähigkeiten unter dem Deckmantel der kompletten Back-to-Front Entwicklung einer (mobilen) Anwendung. Die aktuelle Definition Ihrer Infrastruktur und lokal angepassten Version wird in einem Backend/Ordner als Code und CloudFormation Files innerhalb Ihres App-Repositorys gespeichert. Ähnlich wie git vergleicht es die beiden Zustände, sobald Sie den cli-Befehl „amplify push“ drücken und stellt nur die Änderungen bereit.

Ein Beispiel-Workflow mit Amplify zum Hinzufügen einer Lambda-Funktion zu einem bestehenden Projekt sehen Sie im Folgenden. Die CLI ist eine narrensichere Möglichkeit, Dienste in der Cloud einzurichten und zu verbinden:

amplify add function
? Provide a friendly name for your resource to be used as a label for this category in the project: lambdafunction
? Provide the AWS Lambda function name: lambdafunction
? Choose the function template that you want to use: (Use arrow keys)
❯ Hello world function
  CRUD function for Amazon DynamoDB table (Integration with Amazon API Gateway and Amazon DynamoDB)
  Serverless express function (Integration with Amazon API Gateway)

Vorteile

Cons

Im Allgemeinen sollten Sie zu diesem Zeitpunkt hoffen, dass Sie den Grund für das Scheitern einer der cli-Befehle herausfinden können, da Sie sonst im schlimmsten Fall das Projekt zurücksetzen und neu beginnen müssen. Lassen Sie uns hoffen, dass sich die Fehlerbehandlung der CLI hier verbessern wird.

Empfehlung

Wenn Sie ein kleines oder sogar ein Ein-Mann-Team sind, das schnell eine (mobile) App auf der Basis von (AWS-) Cloud-Ressourcen entwickelt und sich weniger mit DevOps beschäftigen will, ist Amplify eine sehr sichere Wahl. Ich persönlich finde es recht nützlich und benutze es nach wie vor für meine persönlichen Projekte. Ich bin mir jedoch nicht sicher, ob die Verwendung von AWS Amplify in Unternehmensumgebungen eine gute Idee ist, da Sie dazu ermutigt werden, zuerst die CLI zu verwenden, die wiederum nicht versionierbar/rückverfolgbar ist, mit Ausnahme von Änderungen in den CloudFormation Vorlagen.

Transform: AWS::Serverless-2016-10-31
Globals:
  Function:
    PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${AppId}-${AWS::Region}-PermissionsBoundary'

# Paramaters accessible in this template and your handlers
Parameters:
  AppId:
    Type: String
    Default: helloworld-app
  S3BuildBucket:
    Type: String
    Default: arn:aws:s3:::aws-sam-cli-managed-default-samclisourcebucket-13vlf6m4wtxxx

Resources:
  printHelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Path to folder of handlers
      CodeUri: ./src/handlers/
      # <fileName>.<mainFunction>
      Handler: printHelloWorld.printHelloWorldHandler
      Runtime: nodejs10.x
      MemorySize: 128
      Timeout: 60
      Description: A simple example includes a HTTP get method to get all items from a DynamoDB table.
      Policies:
        # Give Create/Read/Update/Delete Permissions to the SampleTable
        - DynamoDBCrudPolicy:
            TableName: !Ref HelloWorldTable
        - S3CrudPolicy:
            BucketName: !Ref S3BuildBucket
      Environment:
        Variables:
          # Make table name accessible as environment variable from function code during execution
          SAMPLE_TABLE: !Ref HelloWorldTable
      Events:
        # Here an Api endpoint is connected
        Api:
          Type: Api
          Properties:
            Path: /helloworld
            Method: GET
            
  # Creates a DynamoDB Table
  HelloWorldTable:
    Type: AWS::Serverless::SimpleTable
    TableName: HelloWorldTable
    Properties:
      PrimaryKey:
        Name: id
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 2
        WriteCapacityUnits: 2

Vorteile

Nachteile

Empfehlung

Man kann SAM als einen Kompromiss zwischen Amplify und CloudFormation sehen. Es gibt praktisch keinen Overhead für Ihre Entwicklungsumgebung im Vergleich zu einem vollwertigen App Framework wie Amplify und gleichzeitig ist es wesentlich einfacher strukturiert als ein pures CloudFormation Skript. Wenn Sie an einer einfachen 3-Tier-Anwendung arbeiten und ohnehin nur Lambda, das API-Gateway und eine NoSQL-Datenbank verwenden würden, können Sie Ihre Anwendung getrost auf SAM aufbauen. Ich fand es auch sehr einfach, das Projekt von der REST-basierten API in SAM zu einer GraphQL-basierten API in Amplify zu migrieren, indem man einfach die Lambda-Handler in die entsprechenden Resolver-Funktionen für die GraphQL-API kopiert (falls nötig).

AWS CDK

Das AWS Cloud Development Kit (AWS CDK) ist ein Open-Source-Softwareentwicklungs-Framework, mit dem Sie Ihre Cloud-Anwendungsressourcen unter Verwendung vertrauter Programmiersprachen definieren können. 

import apigateway = require('@aws-cdk/aws-apigateway'); 
import dynamodb = require('@aws-cdk/aws-dynamodb');
import lambda = require('@aws-cdk/aws-lambda');
import cdk = require('@aws-cdk/core');

export class HelloWorldApp extends cdk.Stack {
  constructor(app: cdk.App, id: string) {
    super(app, id);

    const dynamoTable = new dynamodb.Table(this, 'items', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING
      },
      tableName: 'HelloWorldTable',

      removalPolicy: cdk.RemovalPolicy.DESTROY, // NOT recommended for production code
    });

    const printHelloWorldFunction = new lambda.Function(this, 'printHelloWorldFunction', {
      code: new lambda.AssetCode('./src/handlers/'),
      // <Filename>
      handler: 'printHelloWorld',
      runtime: lambda.Runtime.NODEJS_10_X,
      environment: {
        TABLE_NAME: dynamoTable.tableName,
        PRIMARY_KEY: 'id'
      }
    });
    
    dynamoTable.grantReadWriteData(printHelloWorldFunction);

    const api = new apigateway.RestApi(this, 'helloWorldApi', {
      restApiName: 'HelloWorld Service'
    });

    const helloWorldEndpoint = api.root.addResource('helloWorld');
    const printHelloWorldIntegration = new apigateway.LambdaIntegration(printHelloWorldFunction);
    helloWorldEndpoint.addMethod('GET', printHelloWorldIntegration);
    addCorsOptions(helloWorldEndpoint);
  }
}

// An example how to include some custom CORS Definition programmatically
export function addCorsOptions(apiResource: apigateway.IResource) {
  apiResource.addMethod('OPTIONS', new apigateway.MockIntegration({
    integrationResponses: [{
      statusCode: '200',
      responseParameters: {
        'method.response.header.Access-Control-Allow-Headers': "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent'",
        'method.response.header.Access-Control-Allow-Origin': "'*'",
        'method.response.header.Access-Control-Allow-Credentials': "'false'",
        'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE'",
      },
    }],
    passthroughBehavior: apigateway.PassthroughBehavior.NEVER,
    requestTemplates: {
      "application/json": "{\"statusCode\": 200}"
    },
  }), {
    methodResponses: [{
      statusCode: '200',
      responseParameters: {
        'method.response.header.Access-Control-Allow-Headers': true,
        'method.response.header.Access-Control-Allow-Methods': true,
        'method.response.header.Access-Control-Allow-Credentials': true,
        'method.response.header.Access-Control-Allow-Origin': true,
      },  
    }]
  })
}

const app = new cdk.App();
new HelloWorldApp(app, 'HelloWorldApp');
app.synth();

Sie sehen, dass die Verwendung des CDK etwas mehr Boilerplate Code bedeutet, aber Sie können die Logik auf Ihre eigene gewünschte Weise strukturieren, wie mit der „addCorsOption“-Funktion.

Vorteile

Nachteile

Empfehlung

AWS CDK eignet sich besonders gut für Teams mit Programmiererfahrung, Projekte mit einem Bedarf an einer hochgradig anpassbaren Infrastruktur, die die Entwicklung grundlegender Anwendungen erweitert, und fluktuierende Teams, die eine menschenfreundliche Beschreibung der Infrastruktur für eine schnelle Einarbeitung benötigen. Als Beispiel für diese Vielfalt gibt es bereits eine Open-Source-Erweiterung des CDK für kubernetes „cdk8s“, die mit wenigen Zeilen Code beliebige kubernetes-Konfigurationsdateien im .yaml-Format erzeugen kann. Für einfache Anwendungsbereitstellungen (alias „give me a database and Api“) könnte dies jedoch zu viel Aufwand sein. In einem solchen Fall sind Sie sind mit einer der obigen Lösungen (SAM und Amplify) und mehr Zeit für Entwicklung vermutlich besser dran.

Terraform

Terraform ist ein Werkzeug zum sicheren und effizienten Aufbau, Ändern und Versionieren von Infrastruktur. Terraform kann sowohl bestehende und beliebte Dienstanbieter als auch kundenspezifische Inhouse-Lösungen verwalten. Ein kurzes Beispiel dafür, wie man eine Lambda-Funktion mit einer dynamoDB-Tabelle ohne API-Gateway definiert:

provider "aws" {
   region = "us-east-1"
}

resource "aws_dynamodb_table" "HelloWorld" {
  name             = "HelloWorldTable"
  hash_key         = "id"
  billing_mode   = "PROVISIONED"
  read_capacity  = 5
  write_capacity = 5
  attribute {
    name = "id"
    type = "S"
  }
}

resource "aws_iam_role_policy" "lambda_policy" {
  name = "lambda_policy"
  role = aws_iam_role.role_for_LDC.id

  policy = file("policy.json")
}


resource "aws_iam_role" "role_for_LDC" {
  name = "myrole"
  # policy is stored externally 
  assume_role_policy = file("assume_role_policy.json")

}

resource "aws_lambda_function" "myLambda" {

  function_name = "func"
  s3_bucket     = "mybucket98745"
  s3_key        = "index.zip"
  role          = aws_iam_role.role_for_LDC.arn
  handler       = "printHelloWorldFunction.printHelloWorld"
  runtime       = "nodejs12.x"
}

Vorteile

Nachteile

Empfehlung

Terraform eignet sich als die Einstiegslösung für Multi-Cloud-Roll-outs neben den AWS. Wenn Sie bereits ein Projekt planen, das die App-Entwicklung ausweiten könnte und auf mehreren Cloud-Anbietern basiert, gibt es praktisch keine Alternative zu terraform. Vielleicht sind Sie nicht allzu begeistert davon, eine weitere Syntax (HCL) zu lernen, aber wer weiß, vielleicht haben Sie bereits andere HashiCorp-Produkte verwendet oder werden sie in Zukunft verwenden.

TL/DR

Die genannten Dienstleistungen haben alle ihre individuellen Vor- und Nachteile und bieten in verschiedenen Szenarien einen Mehrwert. Lassen Sie uns in Erinnerung rufen, dass es gerade in der IT-Welt kein „perfektes Framework/Paradigma“ gibt: nur gute Lösungen, die den goldenen Mittelweg zwischen der Abstraktion von sich wiederholenden/komplexen Dingen und der Detaillierung von Dinge die Sie gerne und häufig anpassen wollen.

Um es zusammenzufassen:

Quellen

https://docs.microsoft.com/en-us/azure/devops/learn/what-is-infrastructure-as-code

https://zach-gollwitzer.medium.com/imperative-vs-declarative-programming-procedural-functional-and-oop-b03a53ba745c

https://www.bayesian.ninja/2019/11/aws-cloudformation-pros-and-cons.html

https://www.trustradius.com/products/terraform/reviews?qs=pros-and-cons