Diese 6 Lektionen zur Arbeit mit CloudFormation habe ich für mein ganzes Leben gelernt.

Ich habe vor cloudformation vor 4 Jahren damit angefangen. Seitdem habe ich viele Infrastrukturen beschädigt, sogar solche, die bereits produktiv waren. Aber jedes Mal, wenn ich etwas kaputt gemacht habe, habe ich etwas Neues gelernt. Aus dieser Erfahrung möchte ich einige der wichtigsten Lektionen teilen, die ich gelernt habe.

Diese 6 Lektionen zur Arbeit mit CloudFormation habe ich für mein ganzes Leben gelernt.

Lektion 1: Überprüfen Sie Änderungen, bevor Sie sie bereitstellen.

Diese Lektion habe ich schnell gelernt, nachdem ich mit cloudformationbegonnen habe. Ich kann mich nicht daran erinnern, was genau ich damals kaputt gemacht habe, aber ich erinnere mich genau, dass ich den Befehl aws cloudformation updateverwendet habe. Dieser Befehl führt einfach das Template aus, ohne irgendwelche Änderungen zu überprüfen, die bereitgestellt werden. Ich denke, es bedarf keiner weiteren Erklärung, warum man alle Änderungen überprüfen sollte, bevor man sie bereitstellt.

Nach diesem Misserfolg habe ich sofort die Deployment-Pipelineangepasst und den Befehl update durch den Befehl create-change-set

# 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 Änderungs-Set erstellt wurde, hat es keinen Einfluss auf den bestehenden Stack. Im Gegensatz zum Befehl 'update' führt die Verwendung eines Änderungs-Sets nicht zu einer tatsächlichen Bereitstellung. Stattdessen wird eine Liste von Änderungen erstellt, die Sie vor der Bereitstellung überprüfen können. Sie können die Änderungen über die AWS-Konsole einsehen. Wenn Sie jedoch alles automatisieren möchten, überprüfen Sie sie im 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 erzeugen, die ungefähr wie folgt aussieht:

--------------------------------------------------------------------
|                         DescribeChangeSet                        |
+---------+--------------------+----------------------+------------+
| Aktion  | ReplacementNeeded  |      Ressource       | ResourceId |
+---------+--------------------+----------------------+------------+
|  Ändern | Wahr               |  AWS::ECS::Cluster   |  MyCluster |
|  Ersetzen| Wahr               |  AWS::RDS::DBInstance|  MyDB      |
|  Hinzufügen | Keine           |  AWS::SNS::Topic     |  MyTopic   |
+---------+--------------------+----------------------+------------+

Achten Sie besonders auf Änderungen, bei denen die Aktion Ersetzen, Löschen oder wo ReplacementNeeded — Wahr. Dies sind die gefährlichsten Änderungen und führen normalerweise zu Datenverlust.

Nachdem die Änderungen überprüft wurden, können sie bereitgestellt 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 eine Stack-Policy, um die Ersetzung oder Löschung von Ressourcen während des Status beizubehalten.

Manchmal reicht es nicht aus, die Änderungen einfach zu überprüfen. Wir sind alle Menschen und machen Fehler. Kurz nachdem wir mit der Verwendung von Änderungssets begonnen hatten, führte mein Teamkollege versehentlich ein Deployment durch, was zu einem Update der Datenbank führte. Es passierte nichts Schlimmes, da es sich um eine Testumgebung handelte.

Obwohl unsere Skripte die Liste der Änderungen anzeigten und um Bestätigung baten, wurde die Änderung "Ersetzen" übersehen, da die Liste der Änderungen so groß war, dass sie nicht auf den Bildschirm passte. Da es sich um ein routinemäßiges Update in der Testumgebung handelte, wurde den Änderungen nicht viel Aufmerksamkeit geschenkt.

Es gibt Ressourcen, die Sie niemals ersetzen oder löschen möchten. Dazu gehören zustandsbehaftete Dienste wie eine RDS-Datenbankinstanz oder ein Elasticsearch-Cluster. Es wäre ideal, wenn AWS automatisch das Deployment verweigern würde, wenn die durchgeführte Operation das Löschen solcher Ressourcen erfordert. Glücklicherweise hat CloudFormation eine integrierte Möglichkeit, dies zu tun. Es nennt sich Stack-Policy, und mehr Informationen dazu finden Sie in 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 Stack mit geheimen Parametern aktualisieren

Wenn Sie eine RDS MySQL-Entität erstellen, verlangt AWS von Ihnen, MasterUsername und MasterUserPassword bereitzustellen. Da es besser ist, Geheimnisse nicht im Quellcode zu speichern und ich alles automatisieren wollte, habe ich einen „intelligenten Mechanismus“ implementiert, bei dem die Anmeldedaten vor dem Deployment aus S3 abgerufen werden. Wenn die Anmeldedaten nicht gefunden werden, werden neue Anmeldedaten generiert und in S3 gespeichert.

Anschließend werden diese Anmeldedaten als Parameter an das Team cloudformation create-change-set übergeben. Während ich mit dem Skript experimentierte, kam es vor, dass die Verbindung zu S3 verloren ging, und mein "intelligenter Mechanismus" betrachtete dies als Signal zur Generierung neuer Anmeldedaten.

Wenn ich dieses Skript in einer Produktionsumgebung verwenden würde und erneut ein Verbindungsproblem aufträte, würde es den Stack mit neuen Anmeldedaten aktualisieren. In diesem speziellen Fall würde nichts Schlimmes passieren. Ich habe jedoch von diesem Ansatz Abstand genommen und began, einen anderen zu verwenden, bei dem ich die Anmeldedaten nur einmal – bei der Erstellung des Stacks – bereitstelle. Und später, wenn der Stack ein Update benötigt, würde ich anstelle der Angabe des geheimen Wertes einfach UsePreviousValue=true:

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 Kommando, mit dem ich gearbeitet habe, verwendete eine Funktion cloudformation, die genannt wird Rollback-Konfiguration. Ich habe sie vorher nie getroffen und schnell erkannt, dass das die Bereitstellung meiner Stacks noch beeindruckender machen wird. Jetzt benutze ich es jedes Mal, wenn ich meinen Code in Lambda oder ECS mit CloudFormation bereitstelle.

So funktioniert es: Sie geben an CloudWatch-Alarm-ARN im Parameter —rollback-configuration, wenn Sie ein Änderungsset erstellen. Später, wenn Sie das Änderungsset durchführen, überwacht AWS den Alarm für mindestens eine Minute. Es rollt die Bereitstellung zurück, wenn der Alarm in dieser Zeit den Zustand auf ALARM ändert.

Nachfolgend ein Beispielauszug aus der Vorlage cloudformation, in dem ich einen CloudWatch-Alarmerzeuge, der eine benutzerdefinierte Cloud-Metrik in Form der Anzahl der Fehler in den Cloud-Logs überwacht (die Metrik wird über MetricFilter):

Ressourcen:
  # Diese Metrik verfolgt die Anzahl der Fehler in den CloudWatch-Protokollen. In diesem
  # speziellen Fall wird davon ausgegangen, dass die Protokolle im JSON-Format vorliegen und die Fehlerprotokolle
  # durch das Level "error" identifiziert werden. Siehe FilterPattern
  ErrorMetricFilter:
    Typ: AWS::Logs::MetricFilter
    Eigenschaften:
      LogGroupName: !Ref LogGroup
      FilterPattern: !Sub '{$.level = "error"}'
      MetricTransformations:
      - MetricNamespace: !Sub "${AWS::StackName}-log-errors"
        MetricName: Errors
        MetricValue: 1
        DefaultValue: 0

  ErrorAlarm:
    Typ: AWS::CloudWatch::Alarm
    Eigenschaften:
      AlarmName: !Sub "${AWS::StackName}-errors"
      Namespace: !Sub "${AWS::StackName}-log-errors"
      MetricName: Errors
      Statistik: Maximum
      VergleichsOperator: GreaterThanThreshold
      Zeitraum: 1 # 1 Minute
      EvaluierungsPerioden: 1
      Schwellenwert: 0
      Fehlende Daten behandeln: notBreaching
      Aktionen Aktiviert: ja

Jetzt Alarm kann verwendet werden als Rollback Trigger bei der Ausführung des Toolsets:

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 einfach, eine nicht ganz aktuelle Version der CloudFormation-Vorlage bereitzustellen, aber das kann erhebliche Schäden verursachen. Einmal hatten wir das: Der Entwickler hatte die letzten Änderungen nicht aus Git übermittelt und hat unbewusst eine frühere Version des Stacks bereitgestellt. Das führte zu einem Stillstand der Anwendung, die diesen Stack nutzte.

Eine einfache Maßnahme, wie das Hinzufügen einer Überprüfung, ob der Branch aktuell ist, bevor das Deployment durchgeführt wird, wäre hilfreich (vorausgesetzt, Git ist Ihr Versionskontrolltool):

git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})

if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
   echo "Branch ist nicht auf dem neuesten Stand mit dem Ursprung. Abbruch."
   exit 1
fi

Lektion 6: Erfinden Sie das Rad nicht neu

Es mag so aussehen, als wäre das Deployment mit cloudformation — einfach. Man braucht nur eine Menge Bash-Skripte, die AWS CLI-Befehle ausführen.

Vor 4 Jahren begann ich mit einfachen Skripten, die den Befehl aws cloudformation create-stack aufriefen. Bald war das Skript jedoch nicht mehr einfach. Jede gelernte Lektion machte das Skript immer komplexer. Es war nicht nur kompliziert, sondern auch voller Bugs.

Momentan arbeite ich in einer kleinen IT-Abteilung. Die Erfahrung zeigt, dass jedes Team seine eigene Methode zur Bereitstellung von CloudFormation-Stacks hat. Das ist problematisch. Es wäre besser, wenn alle einen einheitlichen Ansatz verfolgen würden. Glücklicherweise gibt es zahlreiche Tools, die beim Bereitstellen und Konfigurieren von CloudFormation-Stacks helfen.

Diese Lektionen helfen Ihnen, Fehler zu vermeiden.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster