Diese 6 Lektionen der Arbeit mit Cloudformation habe ich für den Rest meines Lebens gelernt.

Ich begann mit zu arbeiten Wolkenbildung vor 4 Jahren. Seitdem habe ich viele Infrastrukturen kaputt gemacht, sogar solche, die bereits in Produktion waren. Aber jedes Mal, wenn ich etwas vermasselte, lernte ich etwas Neues. Durch diese Erfahrung werde ich einige der wichtigsten Lektionen teilen, die ich gelernt habe.

Diese 6 Lektionen der Arbeit mit Cloudformation habe ich für den Rest meines Lebens gelernt.

Lektion 1: Testen Sie Änderungen, bevor Sie sie bereitstellen

Ich habe diese Lektion gelernt, kurz nachdem ich angefangen habe, mit zu arbeiten Wolkenbildung. Ich weiß nicht mehr genau, was ich damals kaputt gemacht habe, aber ich erinnere mich definitiv daran, dass ich den Befehl verwendet habe AWS Cloudformation-Update. Dieser Befehl führt einfach die Vorlage aus, ohne dass die Änderungen, die bereitgestellt werden, überprüft werden. Ich glaube nicht, dass es einer Erklärung bedarf, warum Sie alle Änderungen testen sollten, bevor Sie sie bereitstellen.

Nach diesem Misserfolg habe ich mich sofort verändert Bereitstellungs-Pipeline, wobei der Update-Befehl durch den Befehl ersetzt wird 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"

Sobald ein Changeset erstellt wurde, hat es keine Auswirkungen auf den vorhandenen Stack. Im Gegensatz zum Update-Befehl löst der Changeset-Ansatz nicht die eigentliche Bereitstellung aus. 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 automatisieren möchten, was Sie können, überprüfen Sie dies 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 sich Action befindet Ersetzen, Löschen oder wo ReplacementNeeded – True. Dies sind die gefährlichsten Änderungen und führen in der Regel zu Informationsverlusten.

Sobald 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 Stack-Richtlinien, um zu verhindern, dass zustandsbehaftete Ressourcen ersetzt oder entfernt werden

Manchmal reicht es nicht aus, die Änderungen einfach nur anzusehen. Wir sind alle Menschen und machen alle Fehler. Kurz nachdem wir begonnen hatten, Changesets zu verwenden, führte mein Teamkollege unwissentlich eine Bereitstellung durch, die zu einer Datenbankaktualisierung führte. Da es sich um eine Testumgebung handelte, ist nichts Schlimmes passiert.

Obwohl unsere Skripte eine Liste mit Änderungen anzeigten und um Bestätigung baten, wurde die Änderung „Ersetzen“ übersprungen, da die Liste der Änderungen so umfangreich war, dass sie nicht auf den Bildschirm passte. Und da es sich um ein normales Update in einer Testumgebung handelte, wurde den Änderungen nicht viel Aufmerksamkeit geschenkt.

Es gibt Ressourcen, die Sie niemals ersetzen oder entfernen möchten. Dabei handelt es sich um zustandsbehaftete Dienste, etwa eine RDS-Datenbankinstanz oder einen Elasticsearch-Cluster usw. Es wäre schön, wenn aws die Bereitstellung automatisch verweigern würde, wenn der ausgeführte Vorgang das Löschen einer solchen Ressource erfordern würde. Glücklicherweise verfügt Cloudformation über eine integrierte Möglichkeit, dies zu tun. Dies wird als Stapelrichtlinie bezeichnet. Weitere Informationen hierzu finden Sie unter 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-MySQL-Entität erstellen, verlangt AWS von Ihnen die Angabe eines MasterUsernamens und eines MasterUserPasswords. Da es besser ist, keine Geheimnisse im Quellcode zu behalten und ich absolut alles automatisieren wollte, habe ich einen „intelligenten Mechanismus“ implementiert, bei dem vor der Bereitstellung die Anmeldeinformationen von s3 abgerufen werden und wenn die Anmeldeinformationen nicht gefunden werden, werden neue Anmeldeinformationen generiert und generiert in s3 gespeichert.

Diese Anmeldeinformationen werden dann als Parameter an den Befehl cloudformation create-change-set übergeben. Beim Experimentieren mit dem Skript kam es vor, dass die Verbindung zu s3 unterbrochen wurde und mein „intelligenter Mechanismus“ dies als Signal zur Generierung neuer Anmeldeinformationen interpretierte.

Wenn ich dieses Skript in der Produktion verwende und das Verbindungsproblem erneut auftritt, wird der Stack 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 die Anmeldeinformationen nur einmal angegeben wurden – beim Erstellen des Stacks. Und später, wenn der Stapel aktualisiert werden muss, würde ich, anstatt den geheimen Wert des Parameters anzugeben, einfach verwenden 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: Rollback-Konfiguration verwenden

Ein anderes Team, mit dem ich zusammengearbeitet habe, nutzte die Funktion Wolkenbildungnamens Rollback-Konfiguration. Ich hatte es noch nie zuvor gesehen und erkannte schnell, dass es die Bereitstellung meiner Stacks noch cooler machen würde. Jetzt verwende ich es jedes Mal, wenn ich meinen Code mithilfe von Cloudformation für Lambda oder ECS bereitstelle.

So funktioniert es: Sie bestimmen CloudWatch-Alarm im Parameter --rollback-configurationwenn Sie einen Änderungssatz erstellen. Wenn Sie später eine Reihe von Änderungen durchführen, überwacht aws den Alarm mindestens eine Minute lang. Die Bereitstellung wird rückgängig gemacht, wenn der Alarm während dieser Zeit seinen Status in „ALARM“ ändert.

Nachfolgend finden Sie ein Beispiel für einen Vorlagenauszug Wolkenbildungin dem ich erschaffe Cloudwatch-Alarm, das eine Cloud-Benutzermetrik als Anzahl der Fehler in den Cloud-Protokollen verfolgt (die Metrik wird über generiert). MetrikFilter):

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

im Moment Alarm kann verwendet werden als Rollback Auslöser beim Ausführen der Toolbox:

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 leicht, eine nicht aktuelle Version der Cloudformation-Vorlage bereitzustellen, dies führt jedoch zu großem Schaden. Das ist uns einmal passiert: Ein Entwickler hat die neuesten Änderungen von Git nicht gepusht und unwissentlich eine frühere Version des Stacks bereitgestellt. Dies führte zu Ausfallzeiten für die Anwendung, die diesen Stack verwendete.

Etwas so Einfaches wie das Hinzufügen einer Prüfung, um zu sehen, ob der Zweig auf dem neuesten Stand ist, bevor man ihn festschreibt, wäre in Ordnung (vorausgesetzt, Git ist Ihr Versionskontrolltool):

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: Erfinden Sie das Rad nicht neu

Es mag wie eine Bereitstellung mit erscheinen Wolkenbildung - das ist leicht. Sie benötigen lediglich eine Reihe von Bash-Skripten, die AWS-CLI-Befehle ausführen.

Vor 4 Jahren begann ich mit einfachen Skripten namens aws cloudformation create-stack-Befehl. Bald war das Drehbuch nicht mehr einfach. Mit jeder gewonnenen Lektion wurde das Drehbuch immer komplexer. Es war nicht nur schwierig, sondern auch voller Fehler.

Ich arbeite derzeit in einer kleinen IT-Abteilung. Die Erfahrung hat gezeigt, dass jedes Team seine eigene Art und Weise hat, Cloudformation-Stacks bereitzustellen. Und das ist schlecht. Es wäre besser, wenn alle den gleichen Ansatz verfolgen würden. Glücklicherweise stehen viele Tools zur Verfügung, die Sie bei der Bereitstellung und Konfiguration von Cloudformation-Stacks unterstützen.

Diese Lektionen helfen Ihnen, Fehler zu vermeiden.

Source: habr.com

Kommentar hinzufügen