Kategorien
Amazon AWS

11 AWS Cloudformation Experten Tricks

Bei meiner Arbeit mit Cloudfromation habe ich viel nützliche Tipps gesammelt, die ich gern teilen will.

1. Eine IDE mit Autocomplete verwenden

Für die Jetbrains IDEs wie PHPStorm, Webstorm oder IntelliJ gibt es ein sehr gutes AWS Cloudfromation Plugin namens AWS Cloudfromation von Leonid Shalupov:

AWS Cloudfromation Plugin von Leonid Shalupov

Dieses biete Autocomplete für die IDE an und eine automatische Formatüberprüfung, ob Attribute gesetzt werden, die dort nicht erlaubt sind. Auf diesem weg kann man viele Fehler schon vor dem validieren finden und spart viel Zeit.

AWS Cloudfromation Autocomple

2. AWS-CLI Befehle verwenden

Um die Templates in Cloudfromation zu testen und auch zu deployen sollte man am besten die AWS CLI verwenden um viel Zeit zu sparen.

Die wichtigsten Befehle für Cloudformation sind:

### stack anlegen:
#https://docs.aws.amazon.com/cli/latest/reference/cloudformation/create-stack.html
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

#### template validieren:
aws cloudformation validate-template --template-body file://infrastructure/cloudformation.yml

### status des stacks abrufen:
aws cloudformation describe-stacks --stack-name myteststack

### update stack
aws cloudformation update-stack --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

### delete stack
aws cloudformation delete-stack --stack-name myteststack

## output ändern:
# json, table, text möglich
aws cloudformation describe-stacks --stack-name myteststack --output=text

3. mehrzeiligen Text lesbar schreiben

files:
  /var/www/html/public/index.php:
    content: >-
      <html>
        <body>
          <h1>Welcome to the AWS CloudFormation PHP Sample</h1>
          <p/>
          <?php
            // Print out the current data and time
            print "The Current Date and Time is: <br/>";
            print date("g:i A l, F j Y.");
          ?>
          <?php  phpinfo(); ?>
        </body>
      </html>
    mode: '000600'
    owner: apache
    group: apache

4. Variablen in Strings verwenden

/etc/httpd/conf.d/http-vhost.conf:
  content: !Sub
    - >-
      <Directory "/var/www/html/public">
         Options Indexes FollowSymLinks
         AllowOverride All
         Require all granted
      </Directory>

      <VirtualHost *:80>
         DocumentRoot "/var/www/html/public"
         ServerName "${Domain}"
      </VirtualHost>
    - { Domain: !Ref Domain }

5. Zwei Stacks zum Testen verwenden

Um Zeit zu sparen verwende ich immer 2 Stacks zum Entwickeln, diese werden abwechseln erstellt und gelöscht, weil sonst auf das Löschen des Stacks gewartet werden muss beim Entwickeln.

CLI Befehle:

aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

aws cloudformation delete-stack --stack-name myteststack
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack2

aws cloudformation delete-stack --stack-name myteststack2
aws cloudformation create-stack  --template-body file://infrastructure/cloudformation.yml --stack-name myteststack

....

6. Der Aufbau eines Cloudfromation Templates

Die wichtigste Seite der Cloudformation Dokumentation ist die für den Aufbau eines Cloudformation Templates.

"Resources": {
  "MyInstance": {
    "Type": "AWS::EC2::Instance",
    "Metadata" : {
      "AWS::CloudFormation::Init" : {
        "config" : {
          "packages" : {
            :
          },
          "groups" : {
            :
          },
          "users" : {
            :
          },
          "sources" : {
            :
          },
          "files" : {
            :
          },
          "commands" : {
            :
          },
          "services" : {
            :
          }
        }
      }
    },
    "Properties": {
      :
    }
  }
}

Hier wird u.a. beschrieben, in welcher Reihenfolge die Konfigurationsabschnitte abgearbeitet werden:

  1. packages
  2. groups
  3. users
  4. sources
  5. files
  6. commands
  7. services

In dieser Reihenfolge sollten auch im Template die Konfigurationsabschnitte definiert werden.

7. Cronjob anlegen in Amazon Linux 2

Hier sind 2 Beispiele, wie man für verschiedene User (root und ec2-user) Crontabs anlegt:

InstallCrontab:
 files:
 /var/spool/cron/root:
 content: !Sub |
 # m h dom mon dow command
 39 1,13 * * * certbot renew --no-self-upgrade > /dev/null 2>&1

 mode: '000600'
 owner: root
 group: root

 /var/spool/cron/ec2-user:
 content: !Sub |
 # m h dom mon dow command
 */5 * * * * /usr/local/bin/aws-scripts-mon/mon-put-instance-data.pl --mem-avail --swap-used --disk-space-avail --disk-path=/ --from-cron > /dev/null 2>&1

 mode: '000600'
 owner: ec2-user
 group: ec2-user

 8. yaml oder json

Cloudformation bietet 2 Formate an, die sich tatsächlich sehr unterscheiden, json und yaml. Ich habe mich für yaml entscheiden, weil da weniger zu schreiben ist und der Syntax besser zu lesen. Allerdings habe ich beim Entiwcklen gemerkt, dass fast alle Fragen auf Stackoverflow in json sind, was einen Nachteil dargestellt hat.

Noch besser ist es allerdings:

9. ein Framework verwenden

Leider endet man immer mit einer riesigen Datei in yaml oder json ohne eine Möglichkeit den Inhalt aufzuteilen oder andere Dateien zu inkludieren.

Deswegn würde ich ein Framework wie lono empfehlen, um den Code einfacher zu halten und übersichtlich.

Die Möglichkeit ein Porjekt auf mehrere Dateien aufzusplitten erleichtert auch die Arbeit mit einem VCS wie GIT.

10. Debugging von EC2 Instanz Fehlern

Leider bekommt man oft die wenig sagende Fehlermeldung:

 "Failed to receive 1 resource signal(s) within the specified duration"
Fehlermeldung in der Cloudwatch Oberfläche

Hier sollte man dann das EC2 System Log aufrufen und nach der richtigen Fehlermeldung suchen nach der Stelle „Cloud-init“:

11. Cloudwatch Alarm erstellen mit CloudWatchMonitoringScripts

Um seine Infrastruktur abzusichern, kann man Cloudwatch Alarme erstellen, die einem z.B. per Email (SNS) benachrichten, wenn die CPU Auslastung zu stark ist oder zu wenig freier RAM-Speicher vorhanden ist oder die Festplatte voll läuft.

Um die Daten für die Festplatte un den RAM zu erhalten, muss man die CloudWatchMonitoringScripts installieren und einen Cronjob einrichten.

Dies kann man mit Cloudfromation wie folgt machen:

InstallAwsCloudwatchAgent:
  commands:
    downloadCloudWatchMonitoringScripts:
      command: "sudo curl -o /tmp/CloudWatchMonitoringScripts-1.2.2.zip  https://aws-cloudwatch.s3.amazonaws.com/downloads/CloudWatchMonitoringScripts-1.2.2.zip"

    unzipCloudWatchMonitoringScripts:
      command: "sudo unzip /tmp/CloudWatchMonitoringScripts-1.2.2.zip -d /usr/local/bin"

  packages:
    yum:
      perl-Switch: []
      perl-DateTime: []
      perl-Sys-Syslog: []
      perl-LWP-Protocol-https: []
      perl-Digest-SHA.x86_64: []
  files:
    /var/spool/cron/root:
      content: !Sub |
        # m h dom mon dow      command
        */5 * * * *   /usr/local/bin/aws-scripts-mon/mon-put-instance-data.pl --mem-avail --swap-used  --disk-space-avail --disk-path=/ --from-cron > /dev/null 2>&1

      mode: '000644'
      owner: root
      group: root

Und man kann dann einen Alarm anlegen:

CPUAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyCPUAlarm
    AlarmDescription: CPU alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxx
    MetricName: CPUUtilization
    Namespace: AWS/EC2
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '50'
    ComparisonOperator: GreaterThanThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance

MemoryAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyMemoryAlarm
    AlarmDescription: Memory alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxx
    MetricName: MemoryAvailable
    Namespace: System/Linux
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '200'
    ComparisonOperator: LessThanOrEqualToThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance

DiskSpaceAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: MyDiskSpaceAlarm
    AlarmDescription: Free Disk Space alarm for ec2 instance
    AlarmActions:
      - arn:aws:sns:xxxx
    MetricName: DiskSpaceAvailable
    Namespace: System/Linux
    Statistic: Average
    Period: '300'
    EvaluationPeriods: '3'
    Threshold: '5'
    ComparisonOperator: LessThanOrEqualToThreshold
    TreatMissingData:  missing
    Dimensions:
      - Name: InstanceId
        Value:
          Ref: WebServerInstance
      - Name: Filesystem
        Value: /dev/xvda1
      - Name: MountPath
        Value: /