Por Alessandro Oliveira, Criado em 07/05/2020
O que é o CloudFormation
CloudFormation é antes de mais nada um serviço gerenciado pela AWS que ajuda a organizar as soluções criadas na núvem, é uma peça fundamental para replicar configurações entre ambientes de desenvolvimento, homologação e produção dos clientes, mas também pode ser utilizado para replicar soluções reutilizáveis entre diversos clientes.
Costumo dizer que o CloudFormation sintetiza conhecimento, provisionamento de infraestrutura e horas de troubleshooting em templates de soluções.
Tecnicamente CloudFormation é a forma oficial de definir infraestrutura como código na nuvem da AWS, portanto, é uma peça fundamental para possibilitar processos de entrega contínua e DevOps.
Organização de um template
Um template de cloudformation pode ser definido em um arquivo yaml ou json. Inicialmente os meus templates eram definidos em json, mas ao longo dos últimos 2 anos utilizei apenas yaml por conta da facilidade de leitura.
Exemplo: Infraestrutura Deployment
Em todas as contas AWS que a CloudDog provisiona executamos esse template ou algum derivado dele criando um stack que cria 3 buckets S3 que são compartilhados entre as outras stacks.
Os recursos provisionados por esse stack são:
- LogsBucket: para armazenar logs do Amazon CloudFront ou outro serviço gerenciado que gere logs.
- DeployBucket: utilizado nos processos de continuous deployment para armazenar cópias dos templates de CloudFormation e binários de aplicações que eventualmente são acessados durante os deployments.
- BackupBucket: guarda arquivos de backup que podem ser gerados por outros processos.
CloudFormation template.yml
AWSTemplateFormatVersion: '2010-09-09' Description: Infraestrutura Deployment Resources: LogsBucket: Type: AWS::S3::Bucket
Properties: AccessControl: LogDeliveryWrite DeployBucket: Type: AWS::S3::Bucket
BackupBucket: Type: AWS::S3::Bucket
Outputs: LogsBucketName: Value: !Ref LogsBucket Description: Bucket to store logging in general Export: Name: !Sub ${AWS::StackName}-LogsBucketName DeployBucketName: Value: !Ref DeployBucket Description: Bucket to store deployment artifacts Export: Name: !Sub ${AWS::StackName}-DeployBucketName BackupBucketName: Value: !Ref BackupBucket Description: Bucket to store RDS or any other backup Export: Name: !Sub ${AWS::StackName}-BackupBucketName
As Seções do template
A estrutura completa de um template pode se tornar mais complexa do que essa, mas nesse exemplo já temos as seções mais importantes, que são:
- AWSTemplateFormatVersion: declara a versão do template
- Description: define a descrição do template, que pode ajudar a compreender quando existe uma grande quantidade de stacks
- Resources: onde todos os recursos que devem ser provisionados são declarados
- Outputs: permite a visualização rápida de atributos de recursos criados utilizando a linha de comando e o console da aws. Quando é utilizado o parâmetro export ainda permite que outros stacks façam referência a esses atributos, permitindo um encadeamento de stacks.
Executando o template.yml via console
Selecionar o Serviço CloudFormation
Buscar no menu do console pelo serviço CloudFormation, caso não tenha criado nenhum stack, irá mostrar uma tela parecida com a tela abaixo:
Criar uma Stack
Selecione a opção 'Create Stack' e siga para a próxima tela.
Na sequência deixe configurada a primeira opção: 'Template is Ready', selecione em template source a opção para carregar um template 'Upload a template file', selecione o arquivo conforme a configuração acima e clique em 'Next'.
Configure o 'Stack Name', no nosso exemplo utilizamos infra-deployment mas poderia ser qualquer um que atenda os requisitos da expressão regular descrita abaixo do campo, e clique em 'Next' novamente.
Agora deixe todas as opções como estão, sem nenhuma alteração e clique em 'Next' novamente.
Você poderá no ultimo passo revisar todas as configurações e selecionar a opção 'Create Stack', em seguida verá uma tela parecida com a imagem abaixo com a lista de eventos que foram gerados pelo CloudFormation. Caso dê algum problema, como por exemplo uma configuração inválida, é feito o rollback automaticamente de todo o stack.
Selecionando a aba 'Resources', poderá conferir de forma resumida todos os recursos provisionados.
Selecionando a aba 'Output', poderá conferir todas as variáveis configuradas na seção 'Output' do template, onde o 'Export Name' irá corresponder aos nomes que poderão ser referenciados em outros stacks.
Verificar Recursos Criados
Após a finalização da criação do 'Stack', na aba 'Stack Info' deverá aparecer o Status como CREATE_COMPLETE, na sequência será possível conferir os recursos criados.
Para isso busque no menu de serviços da AWS por S3 ou Simple Storage Service, nesse momento deverá visualizar uma tela semelhante a tela abaixo:
Note que além dos 3 buckets criados pelo template, também foi criado um bucket chamado cf-template-\-us-east-1, esse bucket foi criado pelo próprio CloudFormation no momento em que foi feito o upload do template, caso entre no bucket poderá conferir algo como
Voltando na listagem de buckets e selecionar o bucket de logs, você poderá conferir ele foi criado com uma configuração de 'Permissions' e 'Access Control List' diferenciada onde o S3 Log Delivery Group consta com ambas permissões 'Write Objects' e 'Read Bucket Permissions' como 'yes', conforme pode conferir na próxima imagem:
Nomenclatura
A nomenclatura adotada nos buckets é ${StackName}-${LogicalName}-${HashCode}, onde o StackName é o nome do stack conforme definido no processo de criação, o LogicalName é o nome loógico atribuido na seção 'Resources' do template e o HashCode é gerado automaticamente durante a execução.
Essa nomenclatura a priori pode parecer um pouco esquisita, mas ajuda a manter a organização. Existem alguns serviços, como por exemplo o próprio bucket S3 que utiliza um namespace comum, o que impossibilita a utilização de nomes fixos em diferentes contas.
Atualizando a stack criada anteriormente
Imagine que esqueceu de colocar alguma configuração nesse stack ou evoluiu alguma coisa e precisa replicar isso nos ambientes.
Para manter a infraestrutura como código e deixar os templates alinhados com os stacks, devemos fazer a atualização no template e na sequência criar uma 'Change Set' no stack.
Ajustando o template
Utilizaremos o mesmo cenário do exemplo anterior, como pode ter reparado a essa altura, o LogsBucket está com uma configuração diferenciada para permitir o recebimento de arquivos de log, no entanto, nos outros buckets BackupBucket e DeployBucket não foram feitas as configurações corretamente.
CloudFormation template.yml ajustada
É necessário adicionar as seguintes properties no template original.
DeployBucket: Type: AWS::S3::Bucket
Properties: LoggingConfiguration: DestinationBucketName: !Ref LogsBucket LogFilePrefix: !Sub ${AWS::StackName}/deploy-bucket/ BackupBucket: Type: AWS::S3::Bucket
Properties: LoggingConfiguration: DestinationBucketName: !Ref LogsBucket LogFilePrefix: !Sub ${AWS::StackName}/backup-bucket/
Criando uma Change Set
No serviço CloudFormation no console da AWS, selecione a stack criada anteriormente, no nosso caso infra-deployment, no menu 'Stack Actions' selecione a opção 'Create change set for current stack', conforme a imagem abaixo:
Depois selecione a opção 'Replace current template', para possibilitar o carregamento do template atualizado e faça o carregamento do template utilizando 'Upload a template file' e selecionando o arquivo template.yml.
Na sequência clique em 'Next' aceitando as configurações padrão até aparecer o popup abaixo para configurar o nome do change set, pode deixar o nome sugerido e em seguida clique em 'Create Change Set'.
Após a criação do change set, será possível conferir quais recursos serão alterados por esse change set, se tudo ocorreu bem, deverão aparecer na lista apenas o BackupBucket e o DeployBucket. É importante notar que a coluna 'Replacement' está com valor 'false' para ambos os recursos, isso significa que não haverá perda de dados. Nesse momento, poderá executar a change set com segurança clicando no botão 'Execute'
A change set começará a ser executada e voltará para a aba eventos da Stack, pode clicar no botão refresh até que apareça no topo a linha 'infra-deployment' com status 'UPDATE_COMPLETE', conforme a imagem abaixo.
Validando a Change Set
É sempre importante entrar nos recursos atualizados e conferir que o ajuste foi feito de forma satisfatória.
Protegendo uma Stack
Após a criação e atualização da stack já temos uma base sólida para darmos continuidade e passa a ser importante evitar que alguém exclua essa stack de forma acidental.
Por isso é necessário fazer a configuração selecionando o stack, acesse a opção 'Edit termination protection' no menu 'Stack Actions'
Selecione a opção 'Enable' e confirme clicando em 'Save'.
Poderá conferir na sequência a notificação em verde dizendo que a alteração foi feita com sucesso. Como essa alteração não gerou alterações nos recursos, não houve alteração no status do stack e não foi lançado nenhum evento novo.
Resumo
Nesse artigo descobrimos o básico de um template AWS CloudFormation, criamos uma Stack e atualizamos utilizando uma Change Set, por fim protegemos a stack contra exclusão.