Vaig començar a treballar amb formació de núvols fa 4 anys. Des de llavors he trencat moltes infraestructures, fins i tot les que ja estaven en producció. Però cada vegada que feia malbé alguna cosa, aprenia alguna cosa nova. A través d'aquesta experiència, compartiré algunes de les lliçons més importants que vaig aprendre.
Lliçó 1: prova els canvis abans de desplegar-los
Vaig aprendre aquesta lliçó poc després de començar a treballar formació de núvols. No recordo què vaig trencar exactament aleshores, però definitivament recordo que vaig utilitzar l'ordre actualització aws cloudformation. Aquesta ordre simplement desplega la plantilla sense cap validació dels canvis que es desplegaran. No crec que calgui cap explicació sobre per què hauríeu de provar tots els canvis abans de desplegar-los.
Després d'aquest fracàs, vaig canviar immediatament desplegament pipeline, substituint l'ordre d'actualització per l'ordre crear-canvi-conjunt
# 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"
Un cop creat un conjunt de canvis, no té cap efecte sobre la pila existent. A diferència de l'ordre d'actualització, l'enfocament del conjunt de canvis no activa el desplegament real. En lloc d'això, crea una llista de canvis que podeu revisar abans del desplegament. Podeu veure els canvis a la interfície de la consola aws. Però si preferiu automatitzar tot el que podeu, comproveu-los a la 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
Aquesta ordre hauria de produir una sortida similar a la següent:
--------------------------------------------------------------------
| DescribeChangeSet |
+---------+--------------------+----------------------+------------+
| Action | ReplacementNeeded | Resource | ResourceId |
+---------+--------------------+----------------------+------------+
| Modify | True | AWS::ECS::Cluster | MyCluster |
| Replace| True | AWS::RDS::DBInstance| MyDB |
| Add | None | AWS::SNS::Topic | MyTopic |
+---------+--------------------+----------------------+------------+
Presteu especial atenció als canvis on hi ha Acció Reemplaçar, Esborrar o on Necessitat de substitució: cert. Aquests són els canvis més perillosos i solen conduir a la pèrdua d'informació.
Un cop revisats els canvis, es poden implementar
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"
Lliçó 2: Utilitzeu la política de pila per evitar que els recursos amb estat es substitueixin o s'eliminin
De vegades, simplement veure els canvis no és suficient. Tots som humans i tots ens equivoquem. Poc després de començar a utilitzar conjunts de canvis, el meu company d'equip, sense saber-ho, va realitzar un desplegament que va donar lloc a una actualització de la base de dades. No va passar res dolent perquè era un entorn de proves.
Tot i que els nostres scripts mostraven una llista de canvis i demanaven confirmació, el canvi de substitució es va ometre perquè la llista de canvis era tan gran que no cabia a la pantalla. I com que es tractava d'una actualització normal en un entorn de proves, no es va prestar molta atenció als canvis.
Hi ha recursos que mai no voleu substituir ni eliminar. Es tracta de serveis amb estat complet, com ara una instància de base de dades RDS o un clúster d'Elasticsearch, etc. Seria bo que aws rebutgés automàticament el desplegament si l'operació que s'està realitzant requereix la supressió d'aquest recurs. Afortunadament, Cloudformation té una manera integrada de fer-ho. Això s'anomena política de pila i podeu llegir-ne més informació a
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"
Lliçó 3: Utilitzeu UsePreviousValue quan actualitzeu una pila amb paràmetres secrets
Quan creeu una entitat RDS mysql, AWS requereix que proporcioneu un MasterUsername i una MasterUserPassword. Com que és millor no guardar secrets en el codi font i volia automatitzar-ho absolutament tot, vaig implementar un "mecanisme intel·ligent" on abans del desplegament s'obtindran les credencials de s3, i si no es troben les credencials es generen noves credencials i emmagatzemat a s3.
A continuació, aquestes credencials es passaran com a paràmetres a l'ordre create-change-set de cloudformation. Mentre experimentava amb l'script, va passar que es va perdre la connexió amb s3 i el meu "mecanisme intel·ligent" ho va tractar com un senyal per generar noves credencials.
Si comencés a utilitzar aquest script en producció i el problema de connexió tornés a passar, actualitzaria la pila amb noves credencials. En aquest cas concret, no passarà res dolent. Tanmateix, vaig abandonar aquest enfocament i vaig començar a utilitzar-ne un altre, proporcionant credencials només una vegada, en crear la pila. I més tard, quan la pila necessiti actualitzar, en lloc d'especificar el valor secret del paràmetre, simplement utilitzaria 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"
Lliçó 4: Utilitzeu la configuració de retrocés
Un altre equip amb qui vaig treballar va utilitzar la funció formació de núvols, va trucar configuració de retrocés. No l'havia trobat abans i ràpidament em vaig adonar que faria que el desplegament de les meves piles fos encara més fresc. Ara l'utilitzo cada vegada que implemento el meu codi a lambda o ECS mitjançant Cloudformation.
Com funciona: ho especifiqueu Alarma de CloudWatch en el paràmetre --rollback-configuracióquan creeu un conjunt de canvis. Més tard, quan executeu un conjunt de canvis, aws supervisa l'alarma durant almenys un minut. Es revertirà el desplegament si l'alarma canvia d'estat a ALARMA durant aquest temps.
A continuació es mostra un exemple d'un extracte de plantilla formació de núvolsen el qual jo creo alarma cloudwatch, que fa un seguiment d'una mètrica d'usuari del núvol com a nombre d'errors als registres del núvol (la mètrica es genera mitjançant MetricFilter):
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
Ara alarma es pot utilitzar com a retrocés activador quan s'executa la caixa d'eines:
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"
Lliçó 5: assegureu-vos de desplegar la darrera versió de la plantilla
És fàcil desplegar una versió inferior a la darrera de la plantilla de formació de núvols, però fer-ho causarà molts danys. Això ens va passar una vegada: un desenvolupador no va impulsar els darrers canvis de Git i, sense saber-ho, va desplegar una versió anterior de la pila. Això va provocar temps d'inactivitat per a l'aplicació que utilitzava aquesta pila.
Una cosa tan senzill com afegir una comprovació per veure si la branca està actualitzada abans de comprometre's amb ella estaria bé (suposant que git és la vostra eina de control de versions):
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
Lliçó 6: No reinventis la roda
Pot semblar que es desplega amb formació de núvols - és fàcil. Només necessiteu un munt d'scripts bash que executin ordres aws cli.
Fa 4 anys vaig començar amb scripts senzills anomenats aws cloudformation create-stack command. Aviat el guió ja no era senzill. Cada lliçó apresa feia que el guió fos cada cop més complex. No només va ser difícil, sinó que també va ser ple d'errors.
Actualment treballo en un petit departament informàtic. L'experiència ha demostrat que cada equip té la seva pròpia manera de desplegar les piles de cloudformation. I això és dolent. Seria millor que tothom prengués el mateix enfocament. Afortunadament, hi ha moltes eines disponibles per ajudar-vos a desplegar i configurar les piles de cloudformation.
Aquestes lliçons us ajudaran a evitar errors.
Font: www.habr.com