Aprendi essas 6 lições sobre como trabalhar com cloudformation para o resto da minha vida.

Comecei a trabalhar com formação de nuvens 4 anos atras. Desde então quebrei muitas infraestruturas, mesmo aquelas que já estavam em produção. Mas cada vez que errei alguma coisa, aprendi algo novo. Através desta experiência, compartilharei algumas das lições mais importantes que aprendi.

Aprendi essas 6 lições sobre como trabalhar com cloudformation para o resto da minha vida.

Lição 1: Teste as alterações antes de implantá-las

Aprendi essa lição logo depois que comecei a trabalhar com formação de nuvens. Não me lembro exatamente o que quebrei então, mas definitivamente lembro que usei o comando atualização do aws cloudformation. Este comando simplesmente implementa o modelo sem qualquer validação das alterações que serão implementadas. Não creio que seja necessária qualquer explicação sobre por que você deve testar todas as alterações antes de implantá-las.

Após essa falha, mudei imediatamente pipeline de implantação, substituindo o comando de atualização pelo comando criar-conjunto de alterações

# 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"

Depois que um conjunto de alterações é criado, ele não tem efeito na pilha existente. Ao contrário do comando update, a abordagem changeset não aciona a implantação real. 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 aws. Mas se você preferir automatizar tudo que puder, verifique 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 atenção especial às mudanças onde a Ação é Substituir, Apagar ou onde Substituição necessária - Verdadeiro. Estas são as alterações mais perigosas e geralmente levam à perda de informações.

Depois que as alterações forem revisadas, elas poderão ser implantadas

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 evitar que recursos com estado sejam substituídos ou removidos

Às vezes, simplesmente visualizar as alterações não é suficiente. Somos todos humanos e todos cometemos erros. Pouco depois de começarmos a usar conjuntos de alterações, meu colega de equipe realizou, sem saber, uma implantação que resultou em uma atualização do banco de dados. Nada de ruim aconteceu porque era um ambiente de testes.

Embora nossos scripts exibissem uma lista de alterações e pedissem 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 esta foi uma atualização normal em um ambiente de testes, não foi dada muita atenção às mudanças.

Existem recursos que você nunca deseja substituir ou remover. Esses são serviços statefull, como uma instância de banco de dados RDS ou um cluster elasticsearch, etc. Seria bom se o aws recusasse automaticamente a implantação se a operação executada exigisse a exclusão de tal recurso. Felizmente, o cloudformation tem uma maneira integrada de fazer isso. Isso é chamado de política de pilha e você pode ler mais sobre isso em 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

Ao criar uma entidade RDS mysql, a AWS exige que você forneça um MasterUsername e um MasterUserPassword. Como é melhor não guardar segredos no código fonte e eu queria automatizar absolutamente tudo, implementei um "mecanismo inteligente" onde antes da implantação as credenciais serão obtidas do s3, e caso as credenciais não sejam encontradas, novas credenciais são geradas e armazenado em s3 .

Essas credenciais serão então passadas como parâmetros para o comando create-change-set do cloudformation. Ao experimentar o script, aconteceu que a conexão com o s3 foi perdida e meu “mecanismo inteligente” tratou isso como um sinal para gerar novas credenciais.

Se eu começasse a usar esse script em produção e o problema de conexão acontecesse novamente, ele atualizaria a pilha com novas credenciais. Neste caso específico, nada de ruim acontecerá. Porém, abandonei essa abordagem e comecei a usar outra, fornecendo credenciais apenas uma vez - ao criar a pilha. E mais tarde, quando a pilha precisar ser atualizada, 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 configuração de reversão

Outra equipe com quem trabalhei usou a função formação de nuvenschamado configuração de reversão. Eu não tinha descoberto isso antes e rapidamente percebi que tornaria a implantação de minhas pilhas ainda mais legal. Agora eu o uso sempre que implanto meu código em lambda ou ECS usando cloudformation.

Como funciona: você especifica Alarme CloudWatch no parâmetro --rollback-configuraçãoquando você cria um conjunto de alterações. Posteriormente, quando você executa um conjunto de alterações, o aws monitora o alarme por pelo menos um minuto. Ele reverte a implantação se o alarme mudar de estado para ALARME durante esse período.

Abaixo está um exemplo de trecho de modelo formação de nuvensem que eu crio alarme de nuvem, que rastreia uma métrica do usuário da nuvem como o número de erros nos logs da nuvem (a métrica é gerada via Filtro Métrico):

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 alarme pode ser usado como rollback gatilho ao executar a caixa 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 implementar a versão mais recente do modelo

É fácil implantar uma versão menos recente do modelo cloudformation, mas isso causará muitos danos. Isso aconteceu conosco uma vez: um desenvolvedor não enviou as alterações mais recentes do Git e, sem saber, implantou uma versão anterior da pilha. Isso resultou em tempo de inatividade para o aplicativo que usava essa pilha.

Algo tão simples como adicionar uma verificação para ver se o branch está atualizado antes de se comprometer com ele seria bom (assumindo que o git é 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

Pode parecer que implantar com formação de nuvens - é fácil. Você só precisa de um monte de scripts bash executando comandos aws cli.

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

Atualmente trabalho em um pequeno departamento de TI. A experiência mostra que cada equipe tem sua própria maneira de implantar pilhas de cloudformation. E isso é ruim. Seria melhor se todos adotassem a mesma abordagem. Felizmente, existem muitas ferramentas disponíveis para ajudá-lo a implantar e configurar pilhas de cloudformation.

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

Fonte: habr.com

Adicionar um comentário