Ich
habe vor 4 Jahren angefangen mit
Cloudformation zu arbeiten. Seitdem habe ich viele Infrastrukturen kaputt gemacht, auch solche, die bereits in Produktion waren. Aber jedes Mal, wenn ich etwas verwöhnte, lernte ich neue Dinge. Dank dieser Erfahrung werde ich einige der wichtigsten Lektionen teilen, die ich gelernt habe.

Lektion 1: Überprüfen Sie Änderungen vor der Bereitstellung
Ich habe diese Lektion gelernt, als ich anfing, mit
Cloudformation zu arbeiten . Ich kann mich nicht erinnern, was ich damals kaputt gemacht habe, aber ich erinnere mich genau, dass ich den
Befehl aws cloudformation update verwendet habe . Mit diesem Befehl wird die Vorlage einfach bereitgestellt, ohne dass die Änderungen überprüft werden, die bereitgestellt werden. Ich denke nicht, dass Erklärungen erforderlich sind, für die alle Änderungen überprüft werden müssen, bevor sie bereitgestellt werden.
Nach diesem Fehler habe ich sofort die
Bereitstellungspipeline geändert und den Aktualisierungsbefehl durch den Befehl
create-change-set ersetzt# OPERATION is either "UPDATE" or "CREATE" changeset_id=$(aws cloudformation create-change-set \ --change-set-name "$CHANGE_SET_NAME" \ --stack-name "$STACK_NAME" \ --template-body "$TPL_PATH" \ --change-set-type "$OPERATION" \ --parameters "$PARAMETERS" \ --output text \ --query Id) aws cloudformation wait \ change-set-create-complete --change-set-name "$changeset_id"
Wenn ein Änderungssatz erstellt wird, wirkt sich dies nicht auf den vorhandenen Stapel aus. Im Gegensatz zum Befehl update wird der Change-Set-Ansatz nicht tatsächlich bereitgestellt. Stattdessen wird eine Liste mit Änderungen erstellt, die Sie vor der Bereitstellung überprüfen können. Sie können die Änderungen in der aws-Konsolenoberfläche anzeigen. Wenn Sie jedoch lieber alles Mögliche automatisieren möchten, überprüfen Sie diese in der CLI:
# this command is presented only for demonstrational purposes. # the real command should take pagination into account aws cloudformation describe-change-set \ --change-set-name "$changeset_id" \ --query 'Changes[*].ResourceChange.{Action:Action,Resource:ResourceType,ResourceId:LogicalResourceId,ReplacementNeeded:Replacement}' \ --output table
Dieser Befehl sollte eine Ausgabe ähnlich der folgenden erzeugen:
-------------------------------------------------------------------- | DescribeChangeSet | +---------+--------------------+----------------------+------------+ | Action | ReplacementNeeded | Resource | ResourceId | +---------+--------------------+----------------------+------------+ | Modify | True | AWS::ECS::Cluster | MyCluster | | Replace| True | AWS::RDS::DBInstance| MyDB | | Add | None | AWS::SNS::Topic | MyTopic | +---------+--------------------+----------------------+------------+
Achten Sie besonders auf Änderungen, bei denen Aktion
Ersetzen ,
Löschen oder
Ersetzen erforderlich
ist . Dies sind die gefährlichsten Änderungen und führen normalerweise zum Verlust von Informationen.
Wenn Änderungen angezeigt werden, können sie erweitert werden
aws cloudformation execute-change-set --change-set-name "$changeset_id" operation_lowercase=$(echo "$OPERATION" | tr '[:upper:]' '[:lower:]') aws cloudformation wait "stack-${operation_lowercase}-complete" \ --stack-name "$STACK_NAME"
Lektion 2: Verwenden Sie die Stapelrichtlinie, um das Ersetzen oder Entfernen von Ressourcen zu verhindern
Manchmal reicht es nicht aus, nur die Änderungen zu betrachten. Wir sind alle Menschen und machen alle Fehler. Kurz nachdem wir mit der Verwendung von Änderungssätzen begonnen hatten, führte mein Teamkollege unwissentlich eine Bereitstellung durch, die zu einem Datenbank-Upgrade führte. Es passierte nichts Schreckliches, weil es sich um eine Testumgebung handelte.
Trotz der Tatsache, dass in unseren Skripten eine Liste der Änderungen angezeigt und um Bestätigung gebeten wurde, wurde die Änderung ersetzen übersprungen, da die Liste der Änderungen so groß war, dass sie nicht auf den Bildschirm passen konnte. Und da dies ein regelmäßiges Update in der Testumgebung war, wurde den Änderungen nicht viel Aufmerksamkeit geschenkt.
Es gibt Ressourcen, die Sie niemals ersetzen oder entfernen möchten. Hierbei handelt es sich um statusbehaftete Dienste, z. B. eine Instanz einer RDS-Datenbank oder eines Elastichsearch-Clusters usw. Es wäre schön, wenn aws die Bereitstellung automatisch ablehnen würde, wenn für die ausgeführte Operation das Entfernen einer solchen Ressource erforderlich wäre. Glücklicherweise verfügt Cloudformation über eine integrierte Methode, um dies zu tun. Dies wird als Stapelrichtlinie bezeichnet. Weitere Informationen hierzu finden Sie in der
Dokumentation :
STACK_NAME=$1 RESOURCE_ID=$2 POLICY_JSON=$(cat <<EOF { "Statement" : [{ "Effect" : "Deny", "Action" : [ "Update:Replace", "Update:Delete" ], "Principal": "*", "Resource" : "LogicalResourceId/$RESOURCE_ID" }] } EOF ) aws cloudformation set-stack-policy --stack-name "$STACK_NAME" \ --stack-policy-body "$POLICY_JSON"
Lektion 3: Verwenden Sie UsePreviousValue, wenn Sie einen Stapel mit geheimen Parametern aktualisieren
Wenn Sie eine RDS-Entität erstellen, müssen Sie in mysql AWS MasterUsername und MasterUserPassword angeben. Da es besser ist, keine Geheimnisse im Quellcode zu behalten, und ich absolut alles automatisieren wollte, habe ich einen „intelligenten Mechanismus“ implementiert, bei dem Anmeldeinformationen vor der Bereitstellung von s3 abgerufen werden. Wenn Anmeldeinformationen nicht gefunden werden, werden neue Anmeldeinformationen generiert und in s3 gespeichert .
Diese Anmeldeinformationen werden dann als Parameter an den Befehl cloudformation create-change-set übergeben. Während der Experimente mit dem Skript kam es vor, dass die Verbindung zu s3 unterbrochen wurde, und mein „intelligenter Mechanismus“ betrachtete dies als Signal zum Generieren neuer Anmeldeinformationen.
Wenn ich dieses Skript in einer Produktionsumgebung verwenden würde und das Verbindungsproblem erneut auftreten würde, würde der Stapel mit neuen Anmeldeinformationen aktualisiert. In diesem speziellen Fall wird nichts Schlimmes passieren. Ich habe diesen Ansatz jedoch aufgegeben und einen anderen Ansatz verwendet, bei dem Anmeldeinformationen nur einmal angegeben wurden - beim Erstellen des Stapels. Und später, wenn der Stapel aktualisiert werden muss, anstatt den geheimen Wert des Parameters anzugeben, würde ich einfach
UsePreviousValue = true verwenden :
aws cloudformation create-change-set \ --change-set-name "$CHANGE_SET_NAME" \ --stack-name "$STACK_NAME" \ --template-body "$TPL_PATH" \ --change-set-type "UPDATE" \ --parameters "ParameterKey=MasterUserPassword,UsePreviousValue=true"
Lektion 4: Verwenden Sie die Rollback-Konfiguration
Ein anderes Team, mit dem ich zusammengearbeitet habe, verwendete eine
Cloudformationsfunktion namens
Rollback-Konfiguration . Ich habe sie noch nie zuvor getroffen und schnell erkannt, dass dies die Bereitstellung meiner Stapel noch besser machen würde. Jetzt verwende ich jedes Mal, wenn ich meinen Code in Lambda oder ECS mithilfe von Cloudformation bereitstelle.
So funktioniert es: Sie geben den
CloudWatch- Alarm arn im Parameter
--rollback-configuration an , wenn Sie den Änderungssatz erstellen. Später, wenn Sie den Änderungssatz abgeschlossen haben, verfolgt aws den Alarm mindestens eine Minute lang. Die Bereitstellung wird zurückgesetzt, wenn während dieser Zeit der Alarmstatus in ALARM geändert wird.
Das folgende Beispiel zeigt einen Auszug aus der
Cloudformationsvorlage, in dem ich einen
Cloudwatch-Alarm erstelle, der die Cloud-Metrik des Benutzers als Anzahl der Fehler in den Cloud-Protokollen verfolgt (die Metrik wird über
MetricFilter erstellt ):
Resources: # this metric tracks number of errors in the cloudwatch logs. In this # particular case it's assumed logs are in json format and the error logs are # identified by level "error". See FilterPattern ErrorMetricFilter: Type: AWS::Logs::MetricFilter Properties: LogGroupName: !Ref LogGroup FilterPattern: !Sub '{$.level = "error"}' MetricTransformations: - MetricNamespace: !Sub "${AWS::StackName}-log-errors" MetricName: Errors MetricValue: 1 DefaultValue: 0 ErrorAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: !Sub "${AWS::StackName}-errors" Namespace: !Sub "${AWS::StackName}-log-errors" MetricName: Errors Statistic: Maximum ComparisonOperator: GreaterThanThreshold Period: 1 # 1 minute EvaluationPeriods: 1 Threshold: 0 TreatMissingData: notBreaching ActionsEnabled: yes
Jetzt kann der
Alarm als
Rollback- Trigger verwendet werden, wenn eine Reihe von Tools ausgeführt wird:
ALARM_ARN=$1 ROLLBACK_TRIGGER=$(cat <<EOF { "RollbackTriggers": [ { "Arn": "$ALARM_ARN", "Type": "AWS::CloudWatch::Alarm" } ], "MonitoringTimeInMinutes": 1 } EOF ) aws cloudformation create-change-set \ --change-set-name "$CHANGE_SET_NAME" \ --stack-name "$STACK_NAME" \ --template-body "$TPL_PATH" \ --change-set-type "UPDATE" \ --rollback-configuration "$ROLLBACK_TRIGGER"
Lektion 5: Stellen Sie sicher, dass Sie die neueste Version der Vorlage bereitstellen
Es ist nicht einfach, die neueste Version der Cloudformation-Vorlage bereitzustellen, aber es wird viel Schaden anrichten. Einmal war es bei uns: Der Entwickler hat nicht die neuesten Änderungen von Git gesendet und die vorherige Version des Stacks unwissentlich bereitgestellt. Dies führte zu einer einfachen Anwendung, die diesen Stapel verwendete.
Etwas Einfaches, wie das Hinzufügen einer Überprüfung, ob ein Zweig vor der Bereitstellung relevant ist, ist in Ordnung (vorausgesetzt, Git ist Ihr Tool zur Versionskontrolle):
git fetch HEADHASH=$(git rev-parse HEAD) UPSTREAMHASH=$(git rev-parse master@{upstream}) if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then echo "Branch is not up to date with origin. Aborting" exit 1 fi
Lektion 6: Das Rad nicht neu erfinden
Die Bereitstellung mit
Cloudformation scheint einfach zu sein. Sie benötigen nur eine Reihe von Bash-Skripten, die aws cli-Befehle ausführen.
Vor 4 Jahren begann ich mit einfachen Skripten namens aws cloudformation create-stack command. Bald war das Drehbuch nicht mehr einfach. Jede Lektion machte das Skript immer komplexer. Es war nicht nur schwierig, sondern auch mit einer Reihe von Fehlern.
Jetzt arbeite ich in einer kleinen IT-Abteilung. Die Erfahrung hat gezeigt, dass jedes Team seine eigene Art der Bereitstellung von Cloudformation-Stacks hat. Und das ist schlecht. Es wäre besser, wenn jeder einen einzigen Ansatz verfolgen würde. Glücklicherweise gibt es viele Tools, mit denen Sie Cloudformation-Stacks bereitstellen und konfigurieren können.
Diese Lektionen helfen Ihnen, Fehler zu vermeiden.