Ho imparato queste 6 lezioni lavorando con la formazione delle nuvole per il resto della mia vita.

Ho iniziato a lavorare con formazione della nuvola 4 anni fa. Da allora ho rotto molte infrastrutture, anche quelle che erano già in produzione. Ma ogni volta che sbagliavo qualcosa, imparavo qualcosa di nuovo. Attraverso questa esperienza, condividerò alcune delle lezioni più importanti che ho imparato.

Ho imparato queste 6 lezioni lavorando con la formazione delle nuvole per il resto della mia vita.

Lezione 1: testare le modifiche prima di distribuirle

Ho imparato questa lezione subito dopo aver iniziato a lavorare con formazione della nuvola. Non ricordo esattamente cosa ho rotto allora, ma ricordo sicuramente di aver usato il comando aggiornamento di aws cloudformation. Questo comando distribuisce semplicemente il modello senza alcuna convalida delle modifiche che verranno distribuite. Non penso che sia necessaria alcuna spiegazione sul motivo per cui dovresti testare tutte le modifiche prima di distribuirle.

Dopo questo fallimento, ho subito cambiato pipeline di distribuzione, sostituendo il comando update con il comando crea-modifica-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"

Una volta creato un changeset, non ha alcun effetto sullo stack esistente. A differenza del comando update, l'approccio changeset non attiva la distribuzione effettiva. Crea invece un elenco di modifiche che puoi rivedere prima della distribuzione. Puoi visualizzare le modifiche nell'interfaccia della console AWS. Ma se preferisci automatizzare tutto il possibile, controllali nella 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

Questo comando dovrebbe produrre un output simile al seguente:

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

Presta particolare attenzione ai cambiamenti in cui si trova l'Azione sostituire, Elimina o dove Sostituzione necessaria: vero. Questi sono i cambiamenti più pericolosi e di solito portano alla perdita di informazioni.

Una volta esaminate le modifiche, è possibile implementarle

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"

Lezione 2: utilizzare la policy dello stack per impedire che le risorse con stato vengano sostituite o rimosse

A volte la semplice visualizzazione delle modifiche non è sufficiente. Siamo tutti umani e tutti commettiamo errori. Poco dopo aver iniziato a utilizzare i changeset, il mio compagno di squadra ha eseguito inconsapevolmente una distribuzione che ha comportato un aggiornamento del database. Non è successo niente di male perché era un ambiente di test.

Anche se i nostri script visualizzavano un elenco di modifiche e chiedevano conferma, la modifica Sostituisci è stata saltata perché l'elenco delle modifiche era così grande da non adattarsi allo schermo. E poiché si trattava di un normale aggiornamento in un ambiente di test, non è stata prestata molta attenzione alle modifiche.

Ci sono risorse che non vorresti mai sostituire o rimuovere. Si tratta di servizi con stato, come un'istanza di database RDS o un cluster elasticsearch, ecc. Sarebbe bello se aws rifiutasse automaticamente la distribuzione se l'operazione eseguita richiedesse l'eliminazione di tale risorsa. Fortunatamente, cloudformation ha un modo integrato per farlo. Questa è chiamata politica dello stack e puoi leggere ulteriori informazioni al riguardo in documentazione:

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"

Lezione 3: utilizzare UsePreviousValue durante l'aggiornamento di uno stack con parametri segreti

Quando crei un'entità mysql RDS, AWS richiede di fornire un MasterUsername e una MasterUserPassword. Poiché è meglio non mantenere segreti nel codice sorgente e volevo automatizzare assolutamente tutto, ho implementato un "meccanismo intelligente" in cui prima della distribuzione le credenziali verranno ottenute da s3 e, se le credenziali non vengono trovate, vengono generate nuove credenziali e memorizzato in s3 .

Queste credenziali verranno quindi passate come parametri al comando create-change-set di cloudformation. Durante la sperimentazione dello script, è successo che la connessione a s3 si perdeva e il mio "meccanismo intelligente" lo trattava come un segnale per generare nuove credenziali.

Se iniziassi a utilizzare questo script in produzione e il problema di connessione si ripresentasse, aggiornerebbe lo stack con nuove credenziali. In questo caso particolare, non accadrà nulla di male. Tuttavia, ho abbandonato questo approccio e ho iniziato a utilizzarne un altro, fornendo le credenziali solo una volta, durante la creazione dello stack. E in seguito, quando lo stack necessita di aggiornamento, invece di specificare il valore segreto del parametro, userei semplicemente 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"

Lezione 4: Utilizzare la configurazione di rollback

Un altro team con cui ho lavorato ha utilizzato la funzione formazione della nuvolachiamata configurazione di ripristino. Non l'avevo mai visto prima e ho subito capito che avrebbe reso la distribuzione dei miei stack ancora più interessante. Ora lo uso ogni volta che distribuisco il mio codice su lambda o ECS utilizzando cloudformation.

Come funziona: lo specifichi tu Allarme CloudWatch nel parametro --rollback-configurazionequando crei un changeset. Successivamente, quando esegui una serie di modifiche, aws monitora l'allarme per almeno un minuto. Ripristina la distribuzione se l'allarme cambia lo stato in ALLARME durante questo periodo.

Di seguito è riportato un esempio di estratto di un modello formazione della nuvolain cui creo allarme cloudwatch, che tiene traccia di una metrica utente cloud come numero di errori nei log cloud (la metrica viene generata tramite Filtro metrico):

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

in questo momento allarme può essere utilizzato come rollback trigger durante l'esecuzione della casella degli strumenti:

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"

Lezione 5: Assicurati di distribuire la versione più recente del modello

È facile distribuire una versione meno recente del modello cloudformation, ma ciò causerebbe molti danni. Questo ci è successo una volta: uno sviluppatore non ha inviato le ultime modifiche da Git e ha inconsapevolmente distribuito una versione precedente dello stack. Ciò ha comportato tempi di inattività per l'applicazione che utilizzava questo stack.

Qualcosa di semplice come aggiungere un controllo per vedere se il ramo è aggiornato prima di impegnarsi in esso andrebbe bene (supponendo che git sia il tuo strumento di controllo della versione):

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

Lezione 6: Non reinventare la ruota

Potrebbe sembrare come schierarsi con formazione della nuvola - è facile. Hai solo bisogno di un sacco di script bash che eseguano i comandi aws cli.

4 anni fa ho iniziato con semplici script chiamati comando create-stack di aws cloudformation. Ben presto la sceneggiatura non fu più semplice. Ogni lezione appresa ha reso la sceneggiatura sempre più complessa. Non è stato solo difficile, ma anche pieno di bug.

Attualmente lavoro in un piccolo reparto IT. L'esperienza ha dimostrato che ogni team ha il proprio modo di implementare gli stack di cloudformation. E questo è un male. Sarebbe meglio se tutti adottassero lo stesso approccio. Fortunatamente, sono disponibili molti strumenti per aiutarti a distribuire e configurare stack di cloudformation.

Queste lezioni ti aiuteranno a evitare errori.

Fonte: habr.com

Aggiungi un commento