Počeo sam raditi s cloudformation prije 4 godine. Od tada sam srušio mnogo infrastruktura, čak i one koje su već bile u produkciji. No svaki put kada sam nešto pokvario, naučio sam nešto novo. Na temelju tog iskustva, podijelit ću neka od najvažnijih lekcija koje sam naučio.

Lekcija 1: provjerite promjene prije nego što ih implementirate
Ovu lekciju sam naučio ubrzo nakon što sam počeo raditi s cloudformation. Ne sjećam se točno što sam tada pokvario, ali sigurno se sjećam da sam koristio naredbu aws cloudformation update. Ova naredba jednostavno primjenjuje predložak bez provjere ikakvih promjena koje će biti primijenjene. Ne mislim da su potrebna objašnjenja zašto je bitno provjeriti sve promjene prije nego što ih implementirate.
Nakon ovog neuspjeha, odmah sam promijenio deployment pipeline, zamijenivši naredbu update naredbom 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" Kada je skup promjena kreiran, ne utječe na postojeći stek. Za razliku od naredbe update, pristup korištenjem skupa promjena ne uzrokuje stvarno implementiranje. Umjesto toga, stvara popis promjena koje možete pregledati prije implementacije. Možete pregledati promjene u sučelju konzole aws. Ali ako volite automatizirati sve što možete, provjerite ih u 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 tableOva naredba bi trebala dati izlaz sličan sljedećem:
--------------------------------------------------------------------
| DescribeChangeSet |
+---------+--------------------+----------------------+------------+
| Action | ReplacementNeeded | Resource | ResourceId |
+---------+--------------------+----------------------+------------+
| Modify | True | AWS::ECS::Cluster | MyCluster |
| Replace| True | AWS::RDS::DBInstance| MyDB |
| Add | None | AWS::SNS::Topic | MyTopic |
+---------+--------------------+----------------------+------------+Obratite posebnu pozornost na promjene gdje je Action Replace, Obriši ili gdje ReplacementNeeded — True. Ovo su najopasnije promjene i obično dovode do gubitka informacija.
Kada su promjene pregledane, mogu se implementirati
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: koristite stack policy za sprječavanje zamjene ili brisanja resursa uz održavanje stanja
Ponekad jednostavno pregledavanje promjena nije dovoljno. Svi smo ljudi i svi činimo greške. Ubrzo nakon što smo počeli koristiti setove promjena, moj kolega nenamjerno je izvršio raspoređivanje, što je dovelo do ažuriranja baze podataka. Nije se dogodilo ništa strašno jer je to bilo u testnom okruženju.
Iako su naši skripti prikazivali popis promjena i tražili potvrdu, promjena Replace je propuštena jer je popis promjena bio toliko dug da nije stao na ekran. A s obzirom na to da je to bila obična nadogradnja u testnom okruženju, promjenama se nije pridavala velika pažnja.
Postoje resursi koje nikada ne želite zamijeniti ili ukloniti. To su stateful servisi, poput RDS baze podataka ili elastichsearch klastera itd. Bilo bi dobro kada bi aws automatski odbijo raspoređivanje ako operacija koja se izvodi zahtijeva uklanjanje takvog resursa. Na sreću, cloudformation ima ugrađeni način da to učini. To se zove stack policy, a o tome se više može saznati u :
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: koristite UsePreviousValue kada ažurirate stek s tajnim parametrima
Kada kreirate RDS mysql instancu, AWS od vas zahtijeva da navedete MasterUsername i MasterUserPassword. Budući da je bolje ne čuvati tajne u izvornoj kodu, a ja sam želio automatizirati apsolutno sve, implementirao sam 'pametni mehanizam' u kojem će se prije raspoređivanja podaci preuzeti iz s3, a ako podaci nisu pronađeni, generirat će se novi podaci i pohraniti u s3.
Tada će se ti podaci predati kao parametri timskom cloudformation create-change-set. Tijekom eksperimentiranja sa skriptom dogodilo se da je veza s s3 izgubljena, a moj 'pametni mehanizam' to je smatrao signalom za generiranje novih podataka.
Ako bih počeo koristiti ovu skriptu u radnom okruženju, a problem s povezivanjem bi se ponovno pojavio, ona bi ažurirala stog novim podacima za prijavu. U ovom konkretnom slučaju ne bi se dogodilo ništa loše. Međutim, odustao sam od takvog pristupa i počeo koristiti drugi, pružajući podatke za prijavu samo jednom — prilikom kreiranja stoga. A kasnije, kada stog zatreba ažuriranje, umjesto da navedem tajnu vrijednost parametra, jednostavno bih koristio 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: koristite rollback konfiguraciju
Druga komanda s kojom sam radio koristila je funkciju cloudformation, koja se zove rollback konfiguracija. Prije nisam naišao na nju i brzo sam shvatio da će učiniti implementaciju mojih stogova još boljom. Sada je koristim svaki put kada implementiram svoj kod u lambda ili ECS pomoću cloudformation.
Kako to funkcionira: navodite CloudWatch alarm arn u parametru —rollback-configuration, kada kreirate set promjena. Kasnije, kada izvršavate set promjena, aws prati alarm najmanje jednu minutu. Vraća implementaciju nazad, ako se tokom tog vremena alarm promijeni u stanje ALARM.
U nastavku je primjer dijela predloška cloudformation, u kojem stvaram cloudwatch alarm, koji prati korisničku metriku oblaka u obliku broja grešaka u zapisima oblaka (metrika se stvara kroz MetricFilter):
Resources:
# ova metrika prati broj grešaka u cloudwatch zapisima. U ovom
# slučaju pretpostavlja se da su zapisi u json formatu i da su greške
# identificirane po razini "error". Vidi 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: yesSada alarm može se koristiti kao rollback okidač pri izvršavanju seta alata:
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: osigurajte se da implementirate najnoviju verziju predloška
Lako je implementirati stariju verziju cloudformation predloška, ali to može napraviti veliku štetu. Jednom se dogodilo: programer nije poslao posljednje izmjene iz Gita i nesvjesno je implementirao prethodnu verziju stoga. To je dovelo do zastoja aplikacije koja je koristila taj stog.
Nešto jednostavno, poput dodavanja provjere je li grana ažurirana prije nego što izvodite implementaciju, bit će korisno (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žurirana s originom. Prekidam"
exit 1
fiLekcija 6: ne izmišljajte bicikl
Može se činiti da je implementacija s cloudformation je jednostavna. Samo vam treba hrpa bash skripti koje izvode aws cli komande.
Prije 4 godine počeo sam s jednostavnim skriptama koje nazivaju aws cloudformation create-stack komandu. Ubrzo skripta više nije bila jednostavna. Svaka naučena lekcija činila je skriptu sve složenijom. Nije bilo samo teško, nego i s hrpom grešaka.
Sada radim u malom IT odjelu. Iskustvo pokazuje da svaka ekipa ima svoj način implementacije cloudformation stogova. I to je loše. Bilo bi bolje da svi koriste jedinstveni pristup. Srećom, postoji mnogo alata koji pomažu u implementaciji i konfiguriranju cloudformation stogova.
Ove lekcije pomoći će vam da izbjegnete greške.
Izvor: habr.com
