Teh 6 lekcij dela z cloudformation sem osvojil za vse življenje.

Začel sem delati s cloudformation pred 4 leti. Od takrat sem priklopil veliko infrastrukture, tudi tiste, ki so že bile v produkciji. A vsakič, ko sem kaj pokvaril, sem se naučil novega. Na podlagi te izkušnje bom delil nekaj najpomembnejših lekcij, ki sem se jih naučil.

Teh 6 lekcij dela z cloudformation sem osvojil za vse življenje.

Lekcija 1: preverite spremembe pred uvajanjem

To lekcijo sem usvojil kmalu po tem, ko sem začel delati s cloudformation. Ne spomnim se točno, kaj sem takrat pokvaril, a se dobro spomnim, da sem uporabil ukaz aws cloudformation update. Ta ukaz preprosto uvaja predlogo brez kakršne koli preverbe sprememb, ki bodo uvedene. Mislim, da ni potrebe po razlagi, zakaj je potrebno preveriti vse spremembe pred uvajanjem.

Po tem neuspehu sem takoj spremenil deployment pipeline, tako da sem ukaz update zamenjal z ukazom 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"

Ko je spremembni niz ustvarjen, ne vpliva na obstoječi sklad. Tako kot pri ukazu update, pristop s spremembnim nizom ne povzroči dejanskega uvajanja. Namesto tega ustvari seznam sprememb, ki jih lahko pregledate pred uvajanjem. Spremembe lahko pregledate v vmesniku console aws. Če pa raje vse avtomatizirate, jih preverite v 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

Ta ukaz bi moral vrniti izhod, podoben naslednjemu:

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

Posebno bodite pozorni na spremembe, kjer je Action Zamenjaj, Delete ali kjer ReplacementNeeded — True. To so najnevarnejše spremembe in običajno povzročijo izgubo podatkov.

Ko so spremembe pregledane, jih je mogoče uvajati

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"

Lekcija 2: uporabite politiko sklada za preprečitev zamenjave ali odstranitve virov ob ohranjanju stanja

Včasih preprosto pregledovanje sprememb ni dovolj. Vsi smo ljudje in vsi delamo napake. Takoj po tem, ko smo začeli uporabljati nabor sprememb, je moj sodelavec nenamerno izvedel namestitev, kar je privedlo do posodobitve baze podatkov. Nič hudega ni bilo, saj je šlo za testno okolje.

Kljub temu, da so naši skripti prikazovali seznam sprememb in zahtevali potrditev, je bila sprememba Replace spregledana, ker je bil seznam sprememb tako obsežen, da ni vsega šlo na zaslon. In ker je šlo za običajno posodobitev v testnem okolju, spremembam ni bila namenjena velika pozornost.

Obstajajo viri, ki jih nikoli ne želite zamenjati ali izbrisati. To so statefull storitve, kot je primer baze podatkov RDS ali cluster Elasticsearch itd. Bilo bi lepo, če bi AWS avtomatično zavrnil namestitev, če bi izvedena operacija zahtevala brisanje takega vira. Na srečo CloudFormation ponuja vgrajen način, kako to narediti. To se imenuje politika sklada, o kateri lahko več preberete v dokumenti:

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"

Lekcija 3: uporabite UsePreviousValue, ko posodabljate sklad s tajnimi parametri

Ko ustvarite entiteto RDS MySQL, AWS zahteva, da navedete MasterUsername in MasterUserPassword. Ker je bolje, da skrivnosti ne hranite v izvorni kodi in sem želel avtomatizirati prav vse, sem implementiral 'pameten mehanizem', pri katerem se pred namestitvijo poverilnice pridobijo iz S3, in če poverilnic ni, se generirajo nove in shranijo v S3.

Te poverilnice bodo nato posredovane kot parametri ukazu cloudformation create-change-set. Med eksperimentiranjem s skriptom se je zgodilo, da je povezava s S3 prekinjena, in moj 'pameten mehanizem' je to obravnaval kot signal za generiranje novih poverilnic.

Če bi začel uporabljati ta skript v delovnem okolju in bi se težava s povezavo ponovno pojavila, bi posodobil sklad z novimi poverjenkami. V tem konkretnem primeru se ne bi zgodilo nič slabega. Kljub temu sem se odločil, da takega pristopa ne bom uporabljal in sem začel uporabljati drugega, pri čemer sem poverjenke posredoval samo enkrat — ob ustvarjanju sklada. In kasneje, ko bo sklad potreboval posodobitev, bi namesto da bi navedel skrivno vrednost parametra preprosto uporabil 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"

Lekcija 4: uporabite rollback konfiguracijo

Druga ukazna vrstica, s katero sem delal, je uporabljala funkcijo cloudformation, imenovano rollback configuration. S tem se prej nisem srečal in hitro sem razumel, da bo to moje uvajanje skladov še izboljšalo. Zdaj jo uporabljam vsakič, ko uvajam svojo kodo v lambda ali ECS s pomočjo cloudformation.

Kako to deluje: navedete CloudWatch alarm arn v parametru —rollback-configuration, ko ustvarjate nabor sprememb. Kasneje, ko izvedete nabor sprememb, aws spremlja alarm najmanj eno minuto. Povrne uvajanje nazaj, če se v tem času alarm spremeni v stanje ALARM.

Spodaj je primer odlomka predloge cloudformation, v katerem ustvarjam cloudwatch alarm, ki spremlja lastno metriko oblaka v smislu števila napak v dnevnikih oblaka (metrika se ustvari preko MetricFilter):

Resources:
  # ta metrika sledi številu napak v dnevnikih cloudwatch. V tem
  # primeru se predvideva, da so dnevniki v formatu json in da so napake v dnevnikih
  # zasebne po ravni "error". Oglejte si 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 minuta
      EvaluationPeriods: 1
      Threshold: 0
      TreatMissingData: notBreaching
      ActionsEnabled: yes

Zdaj alarm lahko se uporablja kot rollback triger pri izvajanju niza orodij:

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"

Lekcija 5: Uverite se da implementirate najnoviju verziju šablona

Lako je implementirati stariju verziju cloudformation šablona, ali to može izazvati velike probleme. Imali smo jedan takav slučaj: programer nije poslao najnovije izmene iz Gita i nenamerno je implementirao prethodnu verziju steka. To je dovelo do zastoja aplikacije koja je koristila taj stek.

Nešto jednostavno, poput dodavanja provere da li je grana ažurirana pre nego što izvršite implementaciju, bilo bi dobro (ako pretpostavimo da je git vaš alat za kontrolu verzija):

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

if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
   echo "Grana nije ažurna sa origin-om. Prekidam"
   exit 1
fi

Lekcija 6: Ne izmišljajte tobogan

Može izgledati da je implementacija sa cloudformation — lako. Potrebna vam je samo gomila bash skripti koje izvršavaju aws cli komande.

Pre 4 godine počeo sam sa jednostavnim skriptama koje nazivaju aws cloudformation create-stack komandu. Ubrzo je skripta prestala biti jednostavna. Svaka nova lekcija učinila je skriptu sve složenijom. Nije bilo samo teško, već je bilo i mnogo grešaka.

Sada radim u malom IT timu. Iskustvo pokazuje da svaka ekipa ima svoj način implementacije cloudformation stekova. A to je loše. Bilo bi bolje da svi koriste jedinstven pristup. Na sreću, postoje mnogi alati koji pomažu u implementaciji i podešavanju cloudformation stekova.

Ove lekcije će vam pomoći da izbegnete greške.

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster