Kam fillova të punoj me cloudformation 4 vjet më parë. Që atëherë, kam prishur shumë infrastrukturë, madje edhe ato që ishin në prodhim. Por çdo herë që prisja diçka, merrja diçka të re. Falë kësaj përvoje, do të ndaj disa nga mësimet më të rëndësishme që kam mësuar.

Mësimi 1: kontrolloni ndryshimet para se t'i implementoni
E kam mësuar këtë mësim shpejt pasi fillova të punoj me cloudformation. Nuk e mbaj mend saktësisht se çfarë e kam prishur atëherë, por e mbaj mend që përdora komandën aws cloudformation update. Kjo komandë thjesht hedh poshtë modelin pa ndonjë kontrollim të ndryshimeve që do të implementohen. Nuk mendoj se nevojiten shpjegime përse është e nevojshme të kontrolloni të gjitha ndryshimet para se t'i implementoni ato.
Pas këtij dështimi, menjëherë e kam ndryshuar pipeline-in e implementimit, duke e zëvendësuar komandën update me komandën 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" Kur grupi i ndryshimeve është krijuar, ai nuk ndikon në strukturën ekzistuese. Në krahasim me komandën update, qasja duke përdorur një grup ndryshimesh nuk shkakton implementimin real. Në vend të kësaj, ajo krijon një listë ndryshimesh që mund t'i shikoni para implementimit. Mund t'i shikoni ndryshimet në ndërfaqen e konsolës aws. Por nëse preferoni të automatizoni gjithçka, mund t'i kontrolloni ato në 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 tableKjo komandë duhet të lëshojë një dalje si kjo:
--------------------------------------------------------------------
| DescribeChangeSet |
+---------+--------------------+----------------------+------------+
| Veprimi | ReplacementNeeded | Burimi | ResourceId |
+---------+--------------------+----------------------+------------+
| Modifikoni | True | AWS::ECS::Cluster | MyCluster |
| Zëvendësoni | True | AWS::RDS::DBInstance| MyDB |
| Shto | Asnjë | AWS::SNS::Topic | MyTopic |
+---------+--------------------+----------------------+------------+Kujdesi i veçantë për ndryshimet ku Veprimi është Zëvendëso, Fshi ose ku ReplacementNeeded — True. Këto janë ndryshime shumë të rrezikshme dhe zakonisht çojnë në humbjen e informacionit.
Pasi të jenë shqyrtuar ndryshimet, ato mund të implementohen
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"Mësimi 2: përdorni politikën e stack-ut për të parandaluar zëvendosjen ose fshirjen e burimeve duke ruajtur gjendjen
Ndonjëherë shikimi i asnjë ndryshimi nuk është i mjaftueshëm. Të gjithë jemi njerëz dhe të gjithë bëjmë gabime. Pak pasi filluam të përdorim grupet e ndryshimeve, një koleg i ekipit tim pa dashje e realizoi implementimin, që rezultoi në azhurnimin e bazës së të dhënave. Nuk ndodhi asgjë e keqe, sepse kjo ishte një mjedis testimi.
Megjithëse skriptet tona listonin ndryshimet dhe kërkonin konfirmim, ndryshimi i Zëvendësimit u kalua, sepse lista e ndryshimeve ishte kaq e madhe sa nuk po hynte në ekran. Dhe për të ishte një azhurnim standard në mjedisin e testimit, ndryshimeve vetëm u kushtua pak vëmendje.
Ka burime që nuk do të dëshironit kurrë t'i zëvendësoni ose fshini. Këto janë shërbime me gjendje, siç është instanca e bazës së të dhënave RDS ose klasteri elastichsearch etj. Do të ishte mirë nëse aws do të refuzonte automatikisht implementimin nëse operacioni i kryer do të kërkonte fshirjen e një burimi të tillë. Fatmirësisht, cloudformation ka një mënyrë të integruar për ta bërë këtë. Kjo quhet politika e stack-ut, dhe për këtë mund të lexoni më shumë në :
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"Mësimi 3: përdorni UsePreviousValue kur rinovoni një stack me parametra sekretë
Kur krijoni një entitet RDS mysql, AWS kërkon që të jepni MasterUsername dhe MasterUserPassword. Duke qenë se është më mirë të mos mbani sekretet në kodin burimor, dhe unë doja të automatizoja gjithçka, implementova një "marrëveshje të zgjuar", ku para implementimit, kredencialet do të merreshin nga s3, dhe nëse kredencialet nuk gjendeshin, do të gjeneroheshin të reja dhe do të ruhej në s3.
Më pas, këto kredenciale do të kaloheshin si parametra komandës cloudformation create-change-set. Gjatë eksperimenteve me skriptin, ndodhi që lidhja me s3 u humb, dhe "marrëveshja ime e zgjuar" e konsideroi atë si sinjal për të gjeneruar kredenciale të reja.
Nëse do ta kisha filluar përdorimin e këtij skripti në mjedisin e punës dhe problemi me lidhjen do të ndodhte përsëri, ai do të azhurnonte stack-un me kredenciale të reja. Në këtë rast të veçantë, nuk do të ndodhte asgjë e keqe. Megjithatë, e heqa dorë nga ky qasje dhe fillova të përdor një tjetër, duke dhënë kredencialet vetëm një herë — gjatë krijimit të stack-ut. Dhe më vonë, kur stack-u do të kërkonte azhurnim, do të përdorja thjesht 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"Mësimi 4: përdorni konfigurimin e rikthimit
Një komandë tjetër me të cilën kam punuar përdorte funksionin cloudformation, i quajtur konfigurimi i rikthimit. Nuk kisha hasur më parë me të dhe shpejt e kuptova se do ta bënte shpërndarjen e stekëve të mijëra herë më të bukur. Tani e përdor çdo herë kur shpërndaj kodin tim në lambda ose ECS duke përdorur cloudformation.
Si funksionon: ju specifikoni arn e alarmit të CloudWatch në parametrin --rollback-configuration, kur krijoni një grup ndryshimesh. Më vonë, kur të ekzekutoni grupin e ndryshimeve, aws monitoron alarmi për të paktën një minutë. Ai rikthen shpërndarjen në gjendjen e njohur nëse gjatë kësaj kohe alarmi ndalon në ALARM.
Më poshtë është një shembull i një fragmenti të templates cloudformation, ku krijoj alarmin cloudwatch, duke monitoruar një metrikë të personalizuar të rethit në formën e numrit të gabimeve në logjet e rethit (metrika krijohet nëpërmjet MetricFilter):
Resources:
# kjo metrikë monitoron numrin e gabimeve në logjet e cloudwatch. Në këtë
# rast të veçantë besohet se logjet janë në formatin json dhe logjet e gabimeve identifikohen
# nga niveli "error". Shihni 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 minutë
EvaluationPeriods: 1
Threshold: 0
TreatMissingData: notBreaching
ActionsEnabled: yesTani alarm mund të përdoret si rikthim trigger kur ekzekutoni grupin e mjeteve:
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"Mësimi 5: sigurohuni që po shpërndani versionin më të fundit të templates
Është e lehtë të shpërndash një version jo më të fundit të templates cloudformation, por kjo do të shkaktonte dëme të mëdha. Një herë na ndodhi kështu: një zhvillues nuk e dërgoi ndryshimet më të fundit nga Git dhe pa e kuptuar shpërndau versionin e mëparshëm të stekës. Kjo çoi në një ndërprerje të aplikacionit që përdorte këtë stek.
Diçka e thjeshtë, siç është shtimi i një kontrolli, nëse dega është e përditësuar para se të ekzekutohet shpërndarja, do të jetë e dobishme (nëse supozohet se git është mjeti juaj i menaxhimit të versioneve):
git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})
if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
echo "Dega nuk është e përditësuar me origjinën. Duke abortuar"
exit 1
fiMësimi 6: mos shpikni rrotën
Mund të duken të lehta shpërndarjet me cloudformation -- është e lehtë. Keni nevojë vetëm për një grup skenesh bash, që kryejnë komandat aws cli.
4 vjet më parë fillova me skema të thjeshta që quhen komandë aws cloudformation create-stack. Shpejt skema nuk ishte më e thjeshtë. Çdo mësim i mësuar e bëri skemën gjithnjë e më të komplikuar. Nuk ishte vetëm e vështirë, por po ashtu kishte shumë gabime.
Tani punoj në një departament të vogël IT. Eksperienca tregon se çdo ekip ka mënyrën e vet të shpërndarjes së stekëve cloudformation. Dhe kjo është keq. Do të ishte më mirë nëse të gjithë do të përdornin një qasje të njëjtë. Fatmirësisht, ekzistojnë shumë mjete që ndihmojnë në shpërndarjen dhe konfigurojnë stekët cloudformation.
Këto mësime do t'ju ndihmojnë të shmangni gabimet.
Burimi: habr.com
