Vor einiger Zeit hatte ich das Problem, dass ich gerne EC2 Instanzen um eine bestimmter Uhrzeit Stoppen und Starten will. Das ist zum Beispiel sinnvoll, wenn bestimmte Instanzen nur innerhalb der Arbeitszeit zur Verfügung stehen müssen. Des weiteren wollte ich die Möglichkeiten haben, Instanzen vom Starten und Stoppen über einen Tag auszuschließen.
Inhaltsverzeichnis
Wer sich schon etwas mit AWS beschäftigt hat weiß, dass es immer mehrere Wege gibt ein Problem zu lösen. Ich möchte in diesem Artikel meine Lösung mittels Lambda und CloudWatch zeigen.
Als erste brauchen wir ein Start und ein Stop Script für die EC2 Instanzen. Diese habe ich in Python auf meinem lokalen System realisiert
EC2 Stop Script
Bevor wir mit dem entwickeln starten können, brauchen wir die awscli auf unserem System. Das hat u.A. den Vorteil, dass wir innerhalb des Quellcodes keine Username/Passwort Kombination benötigten, um das ganze auf unserem lokalen System ausführen zu können.
Der Quellcode für das Stop Script sieht dann wie folgt aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import boto3 ec2res = boto3.resource('ec2',region_name='eu-central-1') ec2cli = boto3.client('ec2',region_name='eu-central-1') value_to_find = '24x7' response = ec2cli.describe_instances() ids = [] for reservation in response['Reservations']: for instance in reservation['Instances']: if value_to_find not in [tag['Value'] for tag in instance['Tags']]: ids.append(instance['InstanceId']) instances = ec2res.instances.filter(Filters=[{'Name': 'instance-state-name', 'Values': ['running']}]) inst_list = [] for instance in instances: if instance.id in ids: inst_list.append(instance.id) ec2cli.stop_instances(InstanceIds=inst_list) |
Für alles was mit AWS zu tun hat, verwende ich in Python die Library boto3.
In Zeile 3 und 4 baue ich Verbindungen zu AWS EC2 auf. In Zeile 6 wird der zu suchende Value als Konstante definiert. In Zeile 7 werden Informationen zu allen EC2 Instanzen geholt und zwischengespeichert.
Zeile 9 – 10 beinhalten eine Schleife, welche die IDs der EC2 Instanzen in einer Liste speichert, die keinen Tag mit dem Value 24×7 haben. Hier wird bewusst nur auf das Value Feld geprüft.
In Zeile 16 hole ich alle Informationen zu EC2 Instanzen welche aktuell gestartet sind.
Zeile 20 – 22 dienen dazu eine Liste alle EC2 Instanzen zu erstellen, welche zur Zeit laufen und das entsprechende Value haben. In Zeile 24 werden dann die EC2 Instanzen gestoppt.
EC2 Start Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import boto3 ec2res = boto3.resource('ec2',region_name='eu-central-1') ec2cli = boto3.client('ec2',region_name='eu-central-1') value_to_find = 'workingday' response = ec2cli.describe_instances() ids = [] for reservation in response['Reservations']: for instance in reservation['Instances']: if value_to_find in [tag['Value'] for tag in instance['Tags']]: ids.append(instance['InstanceId']) instances = ec2res.instances.filter(Filters=[{'Name': 'instance-state-name', 'Values': ['stopped']}]) inst_list = [] for instance in instances: if instance.id in ids: inst_list.append(instance.id) ec2cli.start_instances(InstanceIds=inst_list) |
Das Start Script funktioniert im wesentlichen genau so wie das Stop Script. Nur die Konstante in Zeile 6 und der Aufruf in der letzten Zeile wurden angepasst.
AWS IAM und Lambda
Die beiden Scripte alleine sind schon mal sehr hilfreich. Theoretisch könnte man jetzt einen cronjob auf einem System einrichten und das ganze würde funktionieren.
Da wir uns aber hier generell in der Cloud befinden, können wir das ganze auch direkt in der Cloud ausführen. Dafür liefert AWS den sogenannten Lambda dienst. Hier können Scripte hinterlegt und gestartet werden.
Bevor wir eine eigene Lambda Funktion einrichten, braucht man aber als erstes noch eine Rolle, die mit den EC2 Instanzen arbeiten kann. Diese legen wir uns als erstes an
AWS IAM – Anlegen einer EC2 Rolle
Um eine entsprechende Rolle anlegen zu könne wird als erstes die AWS Konsole im Browser aufgerufen. In dem Suchfeld wird anschließend nach IAM gesucht.
Im Menü auf der linken Seite wird der Punkt Rollen ausgewählt. Anschließend muss man auf den Rolle erstellen Button klicken.
In dem Fenster das sich nun öffnet, wird als Rollentyp AWS-Service ausgewählt. Darunter kann man noch im Bereich Häufige Anwendungsfälle den Punkt EC2 auswählen. Danach wird auf den Button mit der Beschriftung Weiter: Berechtigungen geklickt
Wir wollen der Rolle nun zwei Berechtigungen hinzufügen. Die ersten ist eine Standardberechtigungen und kann gesucht werden. Die Berechtigung heißt: AWSLambdaBasicExecutionRole
Die zweite Rolle kann durch einen Klick auf Richtlinie erstellen erstellt werden.
In dem Fenster das sich nun öffnet, wechselt man auf den Reiter JSON. Dort kann der folgende Code eingetragen werden:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "Version": "2020-01-01", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "ec2:RebootInstances", "ec2:DescribeInstances", "ec2:StartInstances", "ec2:DescribeTags", "ec2:StopInstances", "ec2:DescribeInstanceStatus" ], "Resource": "*" } ] } |
Mit diesen Berechtigungen erlaubt man einen eingeschränkten Zugriff auf EC2, welcher für das Starten und Stoppen der Instanzen benötigt wird. Anschließend wird auf den Button Richtlinie überprüfen geklickt.
Als letztes gibt man der Rolle noch einen Namen und klickt auf Richtlinie erstellen.
AWS Lambda – Anlegen einer Lambda Funktion
Schauen wir uns das ganze mal für das Stop Script an. Als erstes muss die AWS Konsole im Browser aufgerufen werden.
In dem neuen Fenster wird anschließend auf den großen orangenen Button oben rechts mit dem Titel Funktion erstellen geklickt.
Hier muss man nun einige Angaben für die Lambda Funktion machen. Als erstes wählt man Ohne Vorgabe erstellen aus. Danach müssen einige Grundlegende Informationen festgelegt werden. Der Name ist frei wählbar. Laufzeit wählt man Python 3.7 aus. Bei der Ausführungsrolle wird eine vorhandene Rolle ausgewählt (siehe oben). Anschließend kann die Funktion erstellt werden.
Nun öffnet sich ein Fenster, um die Lambda Funktion zu definieren. Als erstes wird gleich im Bereich Designer ein Auslöser hinzugefügt.
In dem Fenster für den Auslöser wird als erstes CloudWatch Event/EventBridge ausgewählt. Anschließend muss eine neue Regel erstellt werden. Diese Regel braucht einen Namen. Vom Regeltyp ist es Ausdruck zeitlich planen. Dafür muss ein cron angelegt werden, damit der Auslöser weiß wann er die Lambda Funktion starten soll. Ist alles ausgefüllt, kann man auf den Button Hinzufügen klicken. Bei mir sieht das ganze wie folgt aus:
Anschließend muss im im Designer auf stop-ec2-instanz klicken, um dieses Element wieder zu aktivieren.
Dort muss als nächste der Bereich Funktionscode ausgefüllt werden. Hier wählt man bei Laufzeit Python 3.7 aus. Anschließend kann der Quellcode in das Fenster kopiert werden.
Zu guter letzt wird noch einmal geprüft das die richtige IAM Rolle zugewiesen ist. Dies wird im Bereich Ausführungsrolle eingestellt. Hier wird Verwenden einer vorhandenen Rolle ausgewählt und anschließend die ec2 Rolle hinterlegt.
Damit ist die Lambda Funktion für das Stoppen aller EC2 Instanzen fertig. Das ganze kann man jetzt noch einmal für das Startscript durchführen.
Schreibe einen Kommentar