Deze 6 lessen van het werken met cloudformatie heb ik de rest van mijn leven geleerd.

Ik begon te werken met bewolking 4 jaar geleden. Sindsdien heb ik veel infrastructuur kapot gemaakt, zelfs infrastructuur die al in productie was. Maar elke keer dat ik iets verprutste, leerde ik iets nieuws. Door deze ervaring zal ik enkele van de belangrijkste lessen die ik heb geleerd met u delen.

Deze 6 lessen van het werken met cloudformatie heb ik de rest van mijn leven geleerd.

Les 1: Test wijzigingen voordat u ze implementeert

Deze les heb ik snel geleerd nadat ik ermee begon te werken bewolking. Ik weet niet meer wat ik toen precies heb gebroken, maar ik weet zeker dat ik het commando heb gebruikt aws cloudformatie-update. Met deze opdracht wordt de sjabloon eenvoudigweg uitgerold zonder enige validatie van de wijzigingen die zullen worden geïmplementeerd. Ik denk niet dat er een verklaring nodig is waarom je alle wijzigingen moet testen voordat je ze implementeert.

Na deze mislukking ben ik onmiddellijk veranderd implementatiepijplijn, waarbij de update-opdracht wordt vervangen door de opdracht maak-wijziging-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"

Zodra een wijzigingenset is gemaakt, heeft deze geen effect op de bestaande stapel. In tegenstelling tot de update-opdracht activeert de wijzigingenset-aanpak niet de daadwerkelijke implementatie. In plaats daarvan wordt er een lijst met wijzigingen gemaakt die u kunt bekijken voordat u deze implementeert. U kunt de wijzigingen bekijken in de aws console-interface. Maar als u er de voorkeur aan geeft alles te automatiseren, controleer dit dan in de 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

Deze opdracht zou uitvoer moeten produceren die vergelijkbaar is met het volgende:

--------------------------------------------------------------------
|                         DescribeChangeSet                        |
+---------+--------------------+----------------------+------------+
| Action  | ReplacementNeeded  |      Resource        | ResourceId |
+---------+--------------------+----------------------+------------+
|  Modify | True               |  AWS::ECS::Cluster   |  MyCluster |
|  Replace| True               |  AWS::RDS::DBInstance|  MyDB      |
|  Add    | None               |  AWS::SNS::Topic     |  MyTopic   |
+---------+--------------------+----------------------+------------+

Besteed speciale aandacht aan veranderingen waar Actie is vervangen, Verwijder of waar Vervanging nodig - waar. Dit zijn de gevaarlijkste veranderingen en leiden meestal tot verlies van informatie.

Nadat de wijzigingen zijn beoordeeld, kunnen ze worden geïmplementeerd

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"

Les 2: Gebruik stapelbeleid om te voorkomen dat stateful bronnen worden vervangen of verwijderd

Soms is het simpelweg bekijken van de wijzigingen niet voldoende. We zijn allemaal mensen en we maken allemaal fouten. Kort nadat we wijzigingensets gingen gebruiken, voerde mijn teamgenoot onbewust een implementatie uit die resulteerde in een database-update. Er gebeurde niets ergs omdat het een testomgeving was.

Hoewel onze scripts een lijst met wijzigingen weergaven en om bevestiging vroegen, werd de vervangingswijziging overgeslagen omdat de lijst met wijzigingen zo groot was dat deze niet op het scherm paste. En aangezien dit een normale update was in een testomgeving, werd er niet veel aandacht besteed aan de wijzigingen.

Er zijn bronnen die u nooit wilt vervangen of verwijderen. Dit zijn statefull services, zoals een RDS-database-instantie of een elasticsearch-cluster, enz. Het zou mooi zijn als aws automatisch de implementatie zou weigeren als de uitgevoerde bewerking het verwijderen van een dergelijke bron zou vereisen. Gelukkig heeft cloudformatie een ingebouwde manier om dit te doen. Dit wordt stapelbeleid genoemd en u kunt er meer over lezen in documentatie:

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"

Les 3: Gebruik UsePreviousValue bij het bijwerken van een stapel met geheime parameters

Wanneer u een RDS mysql-entiteit maakt, vereist AWS dat u een MasterUsername en MasterUserPassword opgeeft. Omdat het beter is om geen geheimen te bewaren in de broncode en ik absoluut alles wilde automatiseren, heb ik een "slim mechanisme" geïmplementeerd waarbij vóór de implementatie de inloggegevens worden verkregen uit s3, en als de inloggegevens niet worden gevonden, worden er nieuwe inloggegevens gegenereerd en opgeslagen in s3.

Deze inloggegevens worden vervolgens als parameters doorgegeven aan de opdracht cloudformation create-change-set. Tijdens het experimenteren met het script gebeurde het dat de verbinding met s3 verbroken werd, en mijn “slimme mechanisme” behandelde het als een signaal om nieuwe inloggegevens te genereren.

Als ik dit script in productie zou gaan gebruiken en het verbindingsprobleem opnieuw zou optreden, zou het de stapel bijwerken met nieuwe inloggegevens. In dit specifieke geval zal er niets ergs gebeuren. Ik verliet deze aanpak echter en begon een andere te gebruiken, waarbij ik slechts één keer inloggegevens verstrekte: bij het maken van de stapel. En later, wanneer de stapel moet worden bijgewerkt, zou ik eenvoudigweg gebruiken in plaats van de geheime waarde van de parameter op te geven GebruikVorigeWaarde=waar:

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"

Les 4: Gebruik de rollback-configuratie

Een ander team waarmee ik werkte, gebruikte de functie bewolkinggenaamd configuratie terugdraaien. Ik was het nog niet eerder tegengekomen en besefte al snel dat het het inzetten van mijn stapels nog cooler zou maken. Nu gebruik ik het elke keer als ik mijn code implementeer in lambda of ECS met behulp van cloudformation.

Hoe het werkt: jij bepaalt CloudWatch-alarm arn in de parameter --rollback-configuratiewanneer u een wijzigingenset maakt. Wanneer u later een reeks wijzigingen doorvoert, bewaakt aws het alarm gedurende minimaal één minuut. De implementatie wordt teruggedraaid als het alarm gedurende deze tijd de status verandert in ALARM.

Hieronder ziet u een voorbeeld van een sjabloonfragment bewolkingwaarin ik creëer cloudwatch-alarm, die een cloudgebruikersstatistiek bijhoudt als het aantal fouten in de cloudlogboeken (de statistiek wordt gegenereerd via MetrischFilter):

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

Nu alarm kan worden gebruikt als rollback trigger bij het uitvoeren van 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"

Les 5: Zorg ervoor dat u de nieuwste versie van de sjabloon implementeert

Het is gemakkelijk om een ​​minder dan de nieuwste versie van de cloudformation-sjabloon te implementeren, maar dit zal veel schade aanrichten. Dit is ons een keer overkomen: een ontwikkelaar heeft de laatste wijzigingen uit Git niet gepusht en onbewust een eerdere versie van de stack geïmplementeerd. Dit resulteerde in downtime voor de applicatie die deze stack gebruikte.

Iets eenvoudigs als het toevoegen van een controle om te zien of de branch up-to-date is voordat je je eraan vastlegt, zou prima zijn (ervan uitgaande dat git je versiebeheertool is):

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

Les 6: Vind het wiel niet opnieuw uit

Het lijkt misschien alsof je met bewolking - het is makkelijk. Je hebt gewoon een aantal bash-scripts nodig die aws cli-opdrachten uitvoeren.

4 jaar geleden begon ik met eenvoudige scripts genaamd het aws cloudformation create-stack commando. Al snel was het script niet langer eenvoudig. Elke geleerde les maakte het script steeds complexer. Het was niet alleen moeilijk, maar ook vol bugs.

Momenteel werk ik op een kleine IT-afdeling. De ervaring leert dat elk team zijn eigen manier heeft om cloudformation stacks in te zetten. En dat is slecht. Het zou beter zijn als iedereen dezelfde aanpak hanteerde. Gelukkig zijn er veel tools beschikbaar om u te helpen bij het implementeren en configureren van cloudformation-stacks.

Deze lessen helpen je fouten te voorkomen.

Bron: www.habr.com

Voeg een reactie