Wie stoppe und starte ich Amazon-EC2-Instances mit Lambda in regelmäßigen Intervallen?

Letzte Aktualisierung: 2021.02.15

Ich möchte meine Amazon-Elastic-Compute-Cloud-Nutzung (Amazon EC2) reduzieren, indem ich meine EC2-Instances automatisch beende und starte. Wie verwende ich hierfür AWS Lambda und Amazon CloudWatch Events?

Kurzbeschreibung

Hinweis: Diese Beispielkonfiguration zeigt eine einfache Lösung. Für eine robustere Lösung verwenden Sie den AWS Instance Scheduler. Weitere Informationen finden Sie unter Wie kann ich meine Instances mit dem AWS Instance Scheduler stoppen und starten?

Um EC2-Instances in regelmäßigen Abständen mit Lambda zu stoppen und zu starten, gehen Sie wie folgt vor:

1.    Erstellen Sie eine benutzerdefinierte AWS-Identity-and-Access-Management(IAM)-Richtlinie und Ausführungsrolle für Ihre Lambda-Funktion.

2.    Erstellen Sie Lambda-Funktionen, die Ihre EC2-Instances stoppen und starten.

3.    Testen Sie Ihre Lambda-Funktionen.

4.    Erstellen Sie CloudWatch-Ereignisregeln, die Ihre Funktion nach einem Zeitplan auslösen.
Hinweis: Sie können auch Regeln erstellen, die bei einem Ereignis auslösen, das in Ihrem AWS-Konto stattfindet.

Oder Sie können die AWS-CloudFormation-Vorlage am Ende dieses Artikels verwenden, um das Verfahren zu automatisieren.

Auflösung

Hinweis: Wenn Sie nach Abschluss des folgenden Verfahrens einen Client-Fehler beim Start erhalten, befolgen Sie die Schritte im Artikel zur Fehlerbehebung bei Client-Fehlern beim Start.

Erhalten Sie die IDs der EC2-Instances, die Sie starten und stoppen möchten. Führen Sie danach folgende Aktionen aus:

Erstellen Sie eine IAM-Richtlinie und eine Ausführungsrolle für Ihre Lambda-Funktion

1.    Erstellen einer IAM-Richtlinie mit dem JSON-Richtlinieneditor. Kopieren Sie das folgende JSON-Richtliniendokument und fügen Sie es in den Richtlinieneditor ein:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:Start*",
        "ec2:Stop*"
      ],
      "Resource": "*"
    }
  ]
}

2.    IAM-Rolle für Lambda erstellen.

Wichtig: Stellen Sie beim Anfügen einer Berechtigungsrichtlinie an Lambda sicher, dass Sie die gerade erstellte IAM-Richtlinie auswählen.

Erstellen Sie Lambda-Funktionen, die Ihre EC2-Instances stoppen und starten

1.    Wählen Sie in der AWS-Lambda-Konsole die Option Funktion erstellen.

2.    Wählen Sie Von Grund auf neu verfassen.

3.    Fügen Sie unter Grundlegende Informationen Folgendes hinzu:
Geben Sie für Funktionsname einen Namen ein, der ihn als die Funktion identifiziert, die zum Stoppen Ihrer EC2-Instances verwendet wird. Beispiel: „StopEC2Instances“.
Wählen Sie für Laufzeit Python 3.8.
Erweitern Sie unter Berechtigungen die Option Ausführungsrolle auswählen oder erstellen.
Wählen Sie unter Ausführungsrolle die Option Vorhandene Rolle verwenden.
Wählen Sie unter Vorhandene Rolle die von Ihnen erstellte IAM-Rolle aus.

4.    Wählen Sie Funktion erstellen.

5.    Kopieren Sie unter Funktionscode den folgenden Code und fügen Sie ihn in den Editorbereich im Codeeditor ein (lambda_function). Dieser Code stoppt die von Ihnen identifizierten EC2-Instances.

Beispiel-Funktionscode – Stoppen von EC2-Instances

import boto3
region = 'us-west-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.stop_instances(InstanceIds=instances)
    print('stopped your instances: ' + str(instances))

Wichtig: Ersetzen Sie für Region „us-west-1“ durch die AWS-Region, in der sich Ihre Instances befinden. Ersetzen Sie für Instances die Beispiel-EC2-Instance-IDs durch die IDs der spezifischen Instances, die Sie stoppen und starten möchten.

6.    Stellen Sie unter Grundeinstellungen das Timeout auf 10 Sekunden ein.

Hinweis: Konfigurieren Sie die Lambda-Funktionseinstellungen nach Bedarf für Ihren Anwendungsfall. Wenn Sie beispielsweise mehrere Instances stoppen und starten möchten, benötigen Sie möglicherweise einen anderen Wert für Timeout und Speicher.

7.    Wählen Sie Bereitstellen.

8.    Wiederholen Sie die Schritte 1-7, um eine weitere Funktion zu erstellen. Gehen Sie folgendermaßen vor, damit diese Funktion Ihre EC2-Instances startet:
Geben Sie in Schritt 3 einen anderen Funktionsnamen als den zuvor verwendeten ein. Beispiel: „StartEC2Instances“.
Kopieren Sie in Schritt 5 den folgenden Code und fügen Sie ihn in den Editorbereich des Code-Editors ein (lambda_function):

Beispielfunktionscode – Starten von EC2-Instances

import boto3
region = 'us-west-1'
instances = ['i-12345cb6de4f78g9h', 'i-08ce9b2d7eccf6d26']
ec2 = boto3.client('ec2', region_name=region)

def lambda_handler(event, context):
    ec2.start_instances(InstanceIds=instances)
    print('started your instances: ' + str(instances))

Wichtig: Verwenden Sie für Region und Instances dieselben Werte, die Sie für den Code zum Stoppen Ihrer EC2-Instances verwendet haben.

Testen der Lambda-Funktionen

1.    Wählen Sie in der AWS-Lambda-Konsole die Option Funktionen aus.

2.    Wählen Sie eine der von Ihnen erstellten Funktionen aus.</p> <p>3.

3.    Wählen Sie Testen aus.

4.    Wählen Sie im Dialogfeld Testereignis konfigurieren die Option Neues Testereignis erstellen aus.

5.    Geben Sie einen Ereignisnamen ein. Wählen Sie dann Erstellen.

Hinweis: Sie müssen den JSON-Code für das Testereignis nicht ändern – die Funktion verwendet ihn nicht.

6.    Wählen Sie Testen aus, um die Funktion auszuführen.

7.    Wiederholen Sie die Schritte 1-6 für die andere von Ihnen erstellte Funktion.

Tipp: Sie können den Status Ihrer EC2-Instances vor und nach dem Testen überprüfen, um sicherzustellen, dass Ihre Funktionen wie erwartet funktionieren.

Erstellen Sie CloudWatch-Events-Regeln, die Ihre Lambda-Funktionen auslösen

1.    Öffnen Sie die Amazon-CloudWatch-Konsole.

2.    Wählen Sie im linken Navigationsbereich unter Ereignisse Regeln aus.

3.    Wählen Sie Regel erstellen aus.

4.    Wählen Sie unter Ereignisquelle die Option Planen aus.

5.    Führen Sie einen der folgenden Schritte aus:
Geben Sie für Feste Rate von ein Zeitintervall in Minuten, Stunden oder Tagen ein.
Geben Sie für Cron-Ausdruck einen Ausdruck ein, der Lambda mitteilt, wann Ihre Instances gestoppt werden sollen. Informationen zur Ausdruckssyntax finden Sie unter Ausdrücke für Regeln planen.
Hinweis
: Cron-Ausdrücke werden in UTC ausgewertet. Stellen Sie sicher, dass Sie den Ausdruck für Ihre bevorzugte Zeitzone anpassen.

6.    Wählen Sie unter Ziele die Option Ziel hinzufügen aus.

7.    Wählen Sie Lambda-Funktion aus.

8.    Wählen Sie für Funktion die Funktion aus, die Ihre EC2-Instances stoppt.

9.    Wählen Sie Details konfigurieren aus.

10.    Gehen Sie unter Regeldefinition wie folgt vor:
Geben Sie für Name einen Namen ein, um die Regel zu identifizieren, z. B. „StopEC2Instances“.
(Optional) Geben Sie eine Beschreibung Ihrer Regel ein. Beispiel: „Stoppt EC2-Instances jede Nacht um 22:00 Uhr.“
Wählen Sie für Status das Kontrollkästchen Aktiviert aus.

11.    Wählen Sie Regel erstellen aus.

12.    Wiederholen Sie die Schritte 1 bis 11, um eine Regel zum Starten Ihrer EC2-Instances zu erstellen. Gehen Sie folgendermaßen vor:
Geben Sie in Schritt 5 für Cron-Ausdruck einen Ausdruck ein, der Lambda mitteilt, wann Ihre Instances gestartet werden sollen.
Wählen Sie in Schritt 8 für Funktion die Funktion aus, die Ihre EC2-Instances startet.
Geben Sie in Schritt 10 unter Regeldefinition einen Namen ein, beispielsweise „StartEC2Instances“.
(Optional) Geben Sie eine Beschreibung ein, z. B. „Startet EC2-Instances jeden Morgen um 7 Uhr.“

(Optional) Verwenden Sie eine AWS-CloudFormation-Vorlage zur Automatisierung des Verfahrens

1.    Speichern Sie die folgende AWS-CloudFormation-Vorlage als YAML-Datei.

2.    Speichern Sie die folgende AWS-CloudFormation-Vorlage als YAML-Datei.

3.    Stellen Sie die AWS-CloudFormation-Vorlage in Visual Studio oder der AWS Command Line Interface (AWS-CLI) bereit.

Hinweis: Wenn Sie beim Ausführen von AWS-CLI-Befehlen Fehler erhalten Stellen Sie sicher, dass Sie die neueste Version der AWS-CLI verwenden.

Weitere Informationen zur Verwendung der Vorlage finden Sie unter Arbeiten mit AWS-CloudFormation-Vorlagen.

AWS-CloudFormation-Vorlage zum Stoppen und Starten von EC2-Instances in regelmäßigen Abständen mit Lambda

AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda function with cfn-response.
Parameters: 
  instances: 
    Default: i-12345678
    Description: Instance ID's seperated by commers 
    Type: String
  Region: 
    Description: region only 1 region supported 
    Type: String
  StopScheduled: 
    Default: cron(0 18 ? * MON-FRI *)
    Description: enter an Schedule expression example cron(0 18 ? * MON-FRI *) see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html
    Type: String
  StartScheduled: 
    Default: cron(0 7 ? * MON-FRI *)
    Description: enter an Schedule expression example cron(0 7 ? * MON-FRI * ) see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html
    Type: String
Resources:
  StopEC2Instances:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.8
      Role: !GetAtt Role.Arn
      Handler: index.lambda_handler
      Timeout: 60
      Environment:
         Variables:
          instances: !Ref instances
          Region: !Ref Region
      Code:
        ZipFile: |
          import json
          import re
          import os
          import boto3
          
          def lambda_handler(event, context):
            # TODO implement
            instances_str = os.environ['instances']
            region = os.environ['Region']
            ec2 = boto3.client('ec2', region_name=region)
            instances= re.findall(r"i-[0-9a-z]{17}|i-[0-9a-z]{8}", instances_str)
            print('stopped your instances: ' + str(instances) + "in Region "+ region)
            ec2.stop_instances(InstanceIds=instances)
            
            return {
              'statusCode': 200,
              'body': json.dumps('stopped your instances: ' + str(instances))
            }
      Description: Function that stops instances
  permissionForEventsToInvokeStopEC2Instances:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt StopEC2Instances.Arn
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      "SourceArn" : !GetAtt StopScheduledRule.Arn

  StartEC2Instances:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.8
      Role: !GetAtt Role.Arn
      Handler: index.lambda_handler
      Timeout: 60
      Environment:
         Variables:
          instances: !Ref instances
          Region: !Ref Region
      Code:
        ZipFile: |
          import json
          import re
          import os
          import boto3
          
          def lambda_handler(event, context):
            # TODO implement
            instances_str = os.environ['instances']
            region = os.environ['Region']
            ec2 = boto3.client('ec2', region_name=region)
            instances= re.findall(r"i-[0-9a-z]{17}|i-[0-9a-z]{8}", instances_str)
            print('started your instances: ' + str(instances)+ "in Region "+ region)
            ec2.start_instances(InstanceIds=instances)
            
            return {
              'statusCode': 200,
              'body': json.dumps('started your instances: ' + str(instances))
            }
      Description: Function that started instances
  permissionForEventsToInvokeStartEC2Instances:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt StartEC2Instances.Arn
      Action: lambda:InvokeFunction
      Principal: events.amazonaws.com
      "SourceArn" : !GetAtt StartScheduledRule.Arn

  Role:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      Policies:
        - PolicyName: Ec2permissions
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                - "ec2:StartInstances"
                - "ec2:StopInstances"
                Resource: '*'
                

  StopScheduledRule: 
    Type: AWS::Events::Rule
    Properties: 
      Description: "ScheduledRule"
      ScheduleExpression: !Ref StopScheduled
      State: "ENABLED"
      Targets: 
        - 
          Arn: !GetAtt StopEC2Instances.Arn
          Id: "TargetFunctionV1"
  StartScheduledRule: 
    Type: AWS::Events::Rule
    Properties: 
      Description: "ScheduledRule"
      ScheduleExpression: !Ref StartScheduled
      State: "ENABLED"
      Targets: 
        - 
          Arn: !GetAtt StartEC2Instances.Arn
          Id: "TargetFunctionV1"