Eu aprendi essas 6 lições sobre como trabalhar com a formação de nuvens por toda a vida.

Comecei a trabalhar com cloudformation há 4 anos. Desde então, quebrei muitas infraestruturas, mesmo aquelas que já estavam em produção. Mas toda vez que estragava algo, aprendia coisas novas. Graças a essa experiência, compartilharei algumas das lições mais importantes que aprendi.

imagem

Lição 1: Validar Alterações Antes da Implementação


Aprendi esta lição assim que comecei a trabalhar com a formação de nuvens . Não lembro exatamente o que quebrei na época, mas lembro exatamente que usei o comando aws cloudformation update . Este comando simplesmente lança o modelo sem nenhuma verificação das alterações que serão implantadas. Não acho que sejam necessárias explicações, para as quais você precisa verificar todas as alterações antes de implantá-las.

Após essa falha, alterei imediatamente o pipeline de implementação , substituindo o comando update pelo comando 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" 

Quando um conjunto de alterações é criado, ele não afeta a pilha existente. Ao contrário do comando update, a abordagem do conjunto de alterações não é implementada. Em vez disso, ele cria uma lista de alterações que você pode revisar antes da implantação. Você pode visualizar as alterações na interface do console do aws. Mas se você preferir automatizar tudo o que é possível, verifique-os na 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 

Este comando deve produzir uma saída semelhante à seguinte:

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

Preste especial atenção às alterações em que Ação é Substituir , Excluir ou Substituição Necessária é Verdadeiro . Essas são as mudanças mais perigosas e geralmente levam à perda de informações.

Quando as alterações são exibidas, elas podem ser expandidas

 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" 

Lição 2: use a política de pilha para impedir a substituição ou remoção de estado de recursos


Às vezes, simplesmente visualizar as alterações não é suficiente. Somos todos humanos e todos cometemos erros. Logo após começarmos a usar conjuntos de alterações, meu colega de equipe, sem saber, realizou uma implantação, o que levou a uma atualização do banco de dados. Nada de terrível aconteceu, porque era um ambiente de teste.

Apesar de nossos scripts exibirem uma lista de alterações e solicitarem confirmação, a alteração Substituir foi ignorada porque a lista de alterações era tão grande que não cabia na tela. E como essa era uma atualização regular no ambiente de teste, pouca atenção foi dada às alterações.

Existem recursos que você nunca desejará substituir ou remover. Esses são serviços completos do estado, como uma instância de um banco de dados RDS ou um cluster de pesquisa elástica, etc. Seria bom se o aws se recusasse a implantar automaticamente, se a operação executada exigiria a remoção de um recurso. Felizmente, a formação em nuvem tem uma maneira integrada de fazer isso. Isso é chamado de política de pilha e você pode ler mais sobre isso na documentação :

 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" 

Lição 3: use UsePreviousValue ao atualizar uma pilha com parâmetros secretos


Quando você cria uma entidade RDS, o mysql AWS exige que você forneça MasterUsername e MasterUserPassword. Como é melhor não guardar segredos no código-fonte e eu queria automatizar absolutamente tudo, implementei um “mecanismo inteligente” no qual as credenciais são obtidas do s3 antes da implantação e, se as credenciais não forem encontradas, novas credenciais são geradas e armazenadas no s3 .

Essas credenciais serão passadas como parâmetros para o comando cloudformation create-change-set. Durante os experimentos com o script, aconteceu que a conexão com o s3 foi perdida, e meu “mecanismo inteligente” o considerou um sinal para gerar novas credenciais.

Se eu começar a usar esse script em um ambiente de produção, e o problema de conexão surgir novamente, ele atualizará a pilha com novas credenciais. Nesse caso em particular, nada de ruim vai acontecer. No entanto, abandonei essa abordagem e comecei a usar outra, fornecendo credenciais apenas uma vez - ao criar a pilha. E mais tarde, quando a pilha requer atualização, em vez de especificar o valor secreto do parâmetro, eu simplesmente usaria 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" 

Lição 4: usar a configuração de reversão


Outra equipe com a qual trabalhei estava usando uma função de formação de nuvem chamada configuração de reversão . Eu não a conheci antes e rapidamente percebi que isso tornaria a implantação de minhas pilhas ainda melhor. Agora uso sempre que implanto meu código no lambda ou no ECS usando cloudformation.

Como funciona: você especifica o alarme do CloudWatch no parâmetro --rollback-configuration ao criar o conjunto de alterações. Mais tarde, quando você concluir o conjunto de alterações, o aws rastreia o alarme por pelo menos um minuto. Ele reverte a implantação se, durante esse período, o alarme mudar de estado para ALARM.

A seguir, é apresentado um exemplo de um trecho do modelo de informação na nuvem, no qual crio um alarme de observação na nuvem que rastreia a métrica da nuvem do usuário como o número de erros nos logs da nuvem (a métrica é criada via 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 

Agora, o alarme pode ser usado como um acionador de reversão ao executar um conjunto de ferramentas:

 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" 

Lição 5: certifique-se de implantar a versão mais recente do modelo


Não é fácil implantar a versão mais recente do modelo de formação em nuvem, mas causará muitos danos. Uma vez que estava conosco: o desenvolvedor não enviou as alterações mais recentes do Git e, sem saber, implantou a versão anterior da pilha. Isso levou a um aplicativo simples que usou essa pilha.

Algo simples, como adicionar uma verificação para ver se uma ramificação é relevante antes da implantação, seria bom (supondo que o git seja sua ferramenta de controle de versão):
 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 

Lição 6: não reinvente a roda


A implantação com a formação de nuvens pode parecer fácil. Você só precisa de vários scripts bash que executam comandos aws cli.

Há 4 anos, comecei com scripts simples chamados de comando aws cloudformation create-stack. Logo, o script não era mais simples. Cada lição aprendida tornou o script cada vez mais complexo. Não foi apenas difícil, mas também com um monte de bugs.

Agora eu trabalho em um pequeno departamento de TI. A experiência mostrou que cada equipe tem sua própria maneira de implantar pilhas de informações na nuvem. E isso é ruim. Seria melhor se todos usassem uma única abordagem. Felizmente, existem muitas ferramentas que ajudam a implantar e configurar pilhas de informações na nuvem.

Essas lições ajudarão a evitar erros.

Source: https://habr.com/ru/post/pt446918/


All Articles